package org.springblade.modules.repair.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.core.tool.utils.Func;
import org.springblade.modules.repair.dto.CheckPlanDeptCountDTO;
import org.springblade.modules.repair.dto.CheckPlanTrendQueryDTO;
import org.springblade.modules.repair.dto.PlanCheckStatisticsQueryDTO;
import org.springblade.modules.repair.dto.statistical.DeptGroupDTO;
import org.springblade.modules.repair.dto.statistical.by.CheckStatisticsPlanSimpleDTO;
import org.springblade.modules.repair.entity.*;
import org.springblade.modules.repair.enums.*;
import org.springblade.modules.repair.mapper.MaintainPlanUserDayCountMapper;
import org.springblade.modules.repair.service.*;
import org.springblade.modules.repair.vo.CheckPlanTrendVO;
import org.springblade.modules.repair.vo.CheckPlanUserCountVO;
import org.springblade.modules.repair.vo.PlanUserDayCountVO;
import org.springblade.modules.repair.vo.TaskStatusVO;
import org.springblade.modules.repair.vo.check.PlanCheckStatisticsBuildingPageVO;
import org.springblade.modules.repair.vo.check.PlanCheckStatisticsElevatorListVO;
import org.springblade.modules.repair.vo.statistics.by.*;
import org.springblade.modules.system.entity.User;
import org.springblade.modules.system.service.IDeptService;
import org.springblade.modules.system.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

@AllArgsConstructor
@Service
public class MaintainPlanUserDayCountServiceImpl extends BaseServiceImpl<MaintainPlanUserDayCountMapper, MaintainPlanUserDayCount> implements MaintainPlanUserDayCountService{

	private final IUserService userService;
	private final IDeptService deptService;
	private final IMaintainPlanContentService planContentService;
	private final IMaintainSignService signService;

	@Override
	public List<CheckPlanTrendVO> selectUserCheckPlanTrend(CheckPlanTrendQueryDTO queryDTO) {

		List<CheckPlanTrendVO> resultList = new ArrayList<>();
		// 趋势类型 整体 对比
		if(queryDTO.getDataType().equals(1)){
			// 日 周 月
			if(queryDTO.getTemp().equals(1)){
				List<PlanUserDayCountVO> planUserDayCountList = baseMapper.selectCheckPlanTimeDayCount(queryDTO);
				List<Date> dayList = getDatesBetweenByDay(localDate(queryDTO.getStartTime()),localDate(queryDTO.getEndTime()));
				dayList.forEach(e -> {
					CheckPlanTrendVO entity = new CheckPlanTrendVO();
					entity.setLabel(DateUtil.format(e,"MM/dd"));
					if(ObjectUtil.isNotEmpty(planUserDayCountList)){
						planUserDayCountList.forEach(j -> {
							if(e.compareTo(j.getRecordDate()) == 0){
								BeanUtil.copyProperties(j,entity,CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
								entity.setDurationTotal(BigDecimal.valueOf(j.getDurationTotal()/60).setScale(1,RoundingMode.HALF_UP).doubleValue());
								if(j.getPlanCount() > 0){
									entity.setDurationAverage(BigDecimal.valueOf(j.getDurationTotal()/j.getPlanCount()).setScale(1,RoundingMode.HALF_UP).doubleValue());
								}else {
									entity.setDurationAverage(0.00);
								}
							}
						});
					}
					resultList.add(entity);
				});
			}else if(queryDTO.getTemp().equals(2)){
				Map<String,Date[]> weekMap = getWeekStartAndEnd(queryDTO.getStartTime(),queryDTO.getEndTime());
				weekMap.forEach((k,v) -> {
					CheckPlanTrendVO entity = new CheckPlanTrendVO();
					entity.setLabel(DateUtil.format(v[0],"MM/dd")+"~"+DateUtil.format(v[1],"MM/dd"));
					PlanUserDayCountVO weekCount = baseMapper.selectUserOrDeptCheckPlanTimeWeekCount(v[0],v[1],queryDTO.getUserIds(),queryDTO.getType(),queryDTO.getUseType());
					if(ObjectUtil.isNotEmpty(weekCount)){
						BeanUtil.copyProperties(weekCount,entity,CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
						entity.setDurationTotal(BigDecimal.valueOf(weekCount.getDurationTotal()/60).setScale(1,RoundingMode.HALF_UP).doubleValue());
						if(weekCount.getPlanCount() > 0){
							entity.setDurationAverage(BigDecimal.valueOf(weekCount.getDurationTotal()/weekCount.getPlanCount()).setScale(1,RoundingMode.HALF_UP).doubleValue());
						}else {
							entity.setDurationAverage(0.00);
						}
					}
					resultList.add(entity);
				});
			}else if(queryDTO.getTemp().equals(3)){
				List<Date> monthList = getDatesBetweenByMonth(localDate(queryDTO.getStartTime()),localDate(queryDTO.getEndTime()));
				monthList.forEach(e -> {
					CheckPlanTrendVO entity = new CheckPlanTrendVO();
					entity.setLabel(DateUtil.format(e,"MM")+"月");
					PlanUserDayCountVO monthCount = baseMapper.selectUserOrDeptCheckPlanTimeMonthCount(e,queryDTO.getUserIds(), queryDTO.getType(), queryDTO.getUseType());
					if(ObjectUtil.isNotEmpty(monthCount)){
						BeanUtil.copyProperties(monthCount,entity,CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
						entity.setDurationTotal(BigDecimal.valueOf(monthCount.getDurationTotal()/60).setScale(1,RoundingMode.HALF_UP).doubleValue());
						if(monthCount.getPlanCount() > 0){
							entity.setDurationAverage(BigDecimal.valueOf(monthCount.getDurationTotal()/monthCount.getPlanCount()).setScale(1,RoundingMode.HALF_UP).doubleValue());
						}else {
							entity.setDurationAverage(0.00);
						}
					}
					resultList.add(entity);
				});
			}
		}else if (queryDTO.getDataType().equals(2)){

			List<String> ids = new ArrayList<>();
			if(queryDTO.getType().equals(1)){
				ids = Func.toStrList(queryDTO.getUserIds());
			}else if(queryDTO.getType().equals(2)) {
				ids = Func.toStrList(queryDTO.getDeptIds());
			}
//			// 日
			if(queryDTO.getTemp().equals(1)){
				List<Date> dayList = getDatesBetweenByDay(localDate(queryDTO.getStartTime()),localDate(queryDTO.getEndTime()));
				List<String> finalIds = ids;
				List<CheckPlanTrendVO> temp = new ArrayList<>();
				finalIds.forEach(k -> {
					List<PlanUserDayCountVO> dayCount = null;
					if(queryDTO.getType().equals(1)){
						dayCount = baseMapper.selectUserOrDeptCheckPlanTimeDayCount(k,queryDTO);
					}else if(queryDTO.getType().equals(2)) {
						List<Long> deptIds = deptService.listChildByParentId(k);
						dayCount = baseMapper.selectUserOrDeptCheckPlanTimeDayCount2(deptIds,queryDTO);
					}
					if(ObjectUtil.isNotEmpty(dayCount)){
						dayCount.forEach(e -> {
							CheckPlanTrendVO itemEntity = new CheckPlanTrendVO();
							itemEntity.setId(Long.valueOf(k));
							itemEntity.setRecordDate(e.getRecordDate());
							if(ObjectUtil.isNotEmpty(e) && e.getPlanCount() > 0){
								BeanUtil.copyProperties(e,itemEntity,CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
								itemEntity.setDurationTotal(BigDecimal.valueOf(e.getDurationTotal()/60).setScale(1,RoundingMode.HALF_UP).doubleValue());
								itemEntity.setDurationAverage(BigDecimal.valueOf(e.getDurationTotal()/e.getPlanCount()).setScale(1,RoundingMode.HALF_UP).doubleValue());
							}
							temp.add(itemEntity);
						});
					}
				});
				dayList.forEach(e -> {
					List<CheckPlanTrendVO> item = new ArrayList<>();
					CheckPlanTrendVO entity = new CheckPlanTrendVO();
					entity.setLabel(DateUtil.format(e,"MM/dd"));
					finalIds.forEach(j -> {
						String name = null;
						if(queryDTO.getType().equals(1)){
							name = userService.getById(Long.valueOf(j)).getRealName();
						}else if(queryDTO.getType().equals(2)) {
							name = deptService.getById(Long.valueOf(j)).getDeptName();
						}
						String finalName = name;
						CheckPlanTrendVO itemEntity = new CheckPlanTrendVO();
						itemEntity.setId(Long.valueOf(j));
						itemEntity.setName(finalName);
						if(ObjectUtil.isNotEmpty(temp)){
							temp.forEach(k -> {
								if(DateUtil.between(k.getRecordDate(),e,DateUnit.DAY) == 0 && k.getId().equals(Long.valueOf(j))){
									BeanUtil.copyProperties(k,itemEntity,CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
								}
							});
						}
						item.add(itemEntity);
					});
					entity.setItem(item);
					resultList.add(entity);
				});
			}else if(queryDTO.getTemp().equals(2)){
				Map<String,Date[]> weekMap = getWeekStartAndEnd(queryDTO.getStartTime(),queryDTO.getEndTime());
				List<String> finalIds = ids;
				weekMap.forEach((k,v) -> {
					List<CheckPlanTrendVO> item = new ArrayList<>();
					CheckPlanTrendVO entity = new CheckPlanTrendVO();
					entity.setLabel(DateUtil.format(v[0],"MM/dd")+"~"+DateUtil.format(v[1],"MM/dd"));
					finalIds.forEach(e -> {
						PlanUserDayCountVO weekCount = null;
						CheckPlanTrendVO itemEntity = new CheckPlanTrendVO();
						itemEntity.setId(Long.valueOf(e));
						if(queryDTO.getType().equals(1)){
							weekCount = baseMapper.selectUserOrDeptCheckPlanTimeWeekCount(v[0],v[1],e,queryDTO.getType(),queryDTO.getUseType());
							itemEntity.setName(userService.getById(itemEntity.getId()).getRealName());
						}else if(queryDTO.getType().equals(2)) {
							List<Long> deptIds = deptService.listChildByParentId(e);
							weekCount = baseMapper.selectUserOrDeptCheckPlanTimeWeekCount2(v[0],v[1],deptIds,queryDTO.getType(),queryDTO.getUseType());
							itemEntity.setName(deptService.getById(itemEntity.getId()).getDeptName());
						}
						if(ObjectUtil.isNotEmpty(weekCount) && weekCount.getPlanCount() > 0){
							BeanUtil.copyProperties(weekCount,itemEntity,CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
							itemEntity.setDurationTotal(BigDecimal.valueOf(weekCount.getDurationTotal()/60).setScale(1,RoundingMode.HALF_UP).doubleValue());
							itemEntity.setDurationAverage(BigDecimal.valueOf(weekCount.getDurationTotal()/weekCount.getPlanCount()).setScale(1,RoundingMode.HALF_UP).doubleValue());
						}
						item.add(itemEntity);
					});
					entity.setItem(item);
					resultList.add(entity);
				});
			}else if(queryDTO.getTemp().equals(3)){
				List<Date> monthList = getDatesBetweenByMonth(localDate(queryDTO.getStartTime()),localDate(queryDTO.getEndTime()));
				List<String> finalIds = ids;
				monthList.forEach(e -> {
					List<CheckPlanTrendVO> item = new ArrayList<>();
					CheckPlanTrendVO entity = new CheckPlanTrendVO();
					entity.setLabel(DateUtil.format(e,"MM")+"月");
					finalIds.forEach(j -> {
						CheckPlanTrendVO itemEntity = new CheckPlanTrendVO();
						itemEntity.setId(Long.valueOf(j));
						PlanUserDayCountVO monthCount = null;
						if(queryDTO.getType().equals(1)){
							monthCount = baseMapper.selectUserOrDeptCheckPlanTimeMonthCount(e,j,queryDTO.getType(), queryDTO.getUseType());
							itemEntity.setName(userService.getById(itemEntity.getId()).getRealName());
						}else if(queryDTO.getType().equals(2)) {
							List<Long> deptIds = deptService.listChildByParentId(j);
							monthCount = baseMapper.selectUserOrDeptCheckPlanTimeMonthCount2(e,deptIds,queryDTO.getType(), queryDTO.getUseType());
							itemEntity.setName(deptService.getById(itemEntity.getId()).getDeptName());
						}
						if(ObjectUtil.isNotEmpty(monthCount) && monthCount.getPlanCount() > 0){
							BeanUtil.copyProperties(monthCount,itemEntity,CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
							itemEntity.setDurationTotal(BigDecimal.valueOf(monthCount.getDurationTotal()/60).setScale(1,RoundingMode.HALF_UP).doubleValue());
							itemEntity.setDurationAverage(BigDecimal.valueOf(monthCount.getDurationTotal()/monthCount.getPlanCount()).setScale(1,RoundingMode.HALF_UP).doubleValue());
						}
						item.add(itemEntity);
					});
					entity.setItem(item);
					resultList.add(entity);
				});
			}
		}
		return resultList;
	}

	@Override
	public CheckPlanUserCountVO selectCheckPlanCount(Long userId, String startTime, String endTime, Integer useType) {

		CheckPlanUserCountVO result = baseMapper.selectCheckPlanUserCount(userId,startTime,endTime,useType);
		CheckPlanUserCountVO signCount = baseMapper.selectCheckPlanUserSignCount(userId,startTime,endTime,useType);
		CheckPlanUserCountVO durationTimeliness = baseMapper.selectCheckPlanUserDurationTimeliness(userId,startTime,endTime,useType);
		BeanUtil.copyProperties(signCount,result, CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
		BeanUtil.copyProperties(durationTimeliness,result, CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
		result.setWorkTime(BigDecimal.valueOf(signCount.getWorkTime()/60).setScale(1,RoundingMode.HALF_UP).doubleValue());
		if(result.getPlanCount() > 0){
			result.setWorkTimeAverage(BigDecimal.valueOf(signCount.getWorkTime()/result.getPlanCount()).setScale(1,RoundingMode.HALF_UP).doubleValue());
			result.setDisablePer(BigDecimal.valueOf(result.getDisable()/result.getPlanCount()*100L).setScale(1,RoundingMode.HALF_UP).doubleValue());
			result.setProcessedPer(BigDecimal.valueOf(result.getProcessed()/result.getPlanCount()*100L).setScale(1,RoundingMode.HALF_UP).doubleValue());
			result.setCommitPer(BigDecimal.valueOf(result.getCommit()/result.getPlanCount()*100L).setScale(1,RoundingMode.HALF_UP).doubleValue());
			result.setFinishPer(BigDecimal.valueOf(result.getFinish()/result.getPlanCount()*100L).setScale(2,RoundingMode.HALF_UP).doubleValue());
			result.setTimelinessInTimePer(BigDecimal.valueOf(result.getTimelinessInTime()/result.getPlanCount()*100L).setScale(1,RoundingMode.HALF_UP).doubleValue());
			result.setTimelinessOverduePer(BigDecimal.valueOf(result.getTimelinessOverdue()/result.getPlanCount()*100L).setScale(1,RoundingMode.HALF_UP).doubleValue());
		}else {
			result.setWorkTimeAverage(0.00);
			result.setDisablePer(0.00);
			result.setProcessedPer(0.00);
			result.setCommitPer(0.00);
			result.setFinishPer(0.00);
			result.setTimelinessInTimePer(0.00);
			result.setTimelinessOverduePer(0.00);
		}
		if(result.getPlanCommitCount() > 0){
			result.setDurationNormalPer(BigDecimal.valueOf(result.getDurationNormal()/result.getPlanCommitCount()*100L).setScale(1,RoundingMode.HALF_UP).doubleValue());
			result.setDurationTooLongPer(BigDecimal.valueOf(result.getDurationTooLong()/result.getPlanCommitCount()*100L).setScale(1,RoundingMode.HALF_UP).doubleValue());
			result.setDurationTooShortPer(BigDecimal.valueOf(result.getDurationTooShort()/result.getPlanCommitCount()*100L).setScale(1,RoundingMode.HALF_UP).doubleValue());
		}else {
			result.setDurationNormalPer(0.00);
			result.setDurationTooLongPer(0.00);
			result.setDurationTooShortPer(0.00);
		}
		if(result.getSignCount() > 0){
			result.setSignNormalPer(BigDecimal.valueOf(result.getSignNormal()/result.getSignCount()*100L).setScale(1,RoundingMode.HALF_UP).doubleValue());
			result.setSignErrorPer(BigDecimal.valueOf(result.getSignError()/result.getSignCount()*100L).setScale(1,RoundingMode.HALF_UP).doubleValue());
			result.setSignOutErrorPer(BigDecimal.valueOf(result.getSignOutError()/result.getSignCount()*100L).setScale(1,RoundingMode.HALF_UP).doubleValue());
			result.setSignSystemPer(BigDecimal.valueOf(result.getSignSystem()/result.getSignCount()*100L).setScale(1,RoundingMode.HALF_UP).doubleValue());
		}else {
			result.setSignNormalPer(0.00);
			result.setSignErrorPer(0.00);
			result.setSignOutErrorPer(0.00);
			result.setSignSystemPer(0.00);
		}

		return result;
	}

	@Override
	public CheckPlanUserCountVO selectCheckPlanDeptCount(CheckPlanDeptCountDTO queryDTO) {
		List<CheckPlanUserCountVO> deptList = new ArrayList<>();
		List<CheckPlanUserCountVO> userList = new ArrayList<>();

		List<Long> allUserIds = new ArrayList<>();
		queryDTO.getItem().forEach(e -> {

			List<Long> deptUserIds = e.getItem().stream().map(CheckPlanDeptCountDTO::getId).collect(Collectors.toList());
			allUserIds.addAll(deptUserIds);
			CheckPlanUserCountVO deptResult = baseMapper.selectCheckPlanDeptCount(deptUserIds,queryDTO);
			CheckPlanUserCountVO deptSignCount = baseMapper.selectCheckPlanDeptSignCount(deptUserIds,queryDTO);
			CheckPlanUserCountVO deptDurationTimeliness = baseMapper.selectCheckPlanDeptDurationTimeliness(deptUserIds,queryDTO);
			change(deptResult, deptSignCount, deptDurationTimeliness);
			if(e.getId().equals(1L)){
				deptResult.setLabel("未分组");
			}else {
				deptResult.setLabel(deptService.getById(e.getId()).getDeptName());
			}
			deptList.add(deptResult);

			deptUserIds.forEach(j -> {
				CheckPlanUserCountVO result = baseMapper.selectCheckPlanUserCount(j,queryDTO.getStartTime(),queryDTO.getEndTime(),queryDTO.getUseType());
				CheckPlanUserCountVO signCount = baseMapper.selectCheckPlanUserSignCount(j,queryDTO.getStartTime(),queryDTO.getEndTime(), queryDTO.getUseType());
				CheckPlanUserCountVO durationTimeliness = baseMapper.selectCheckPlanUserDurationTimeliness(j,queryDTO.getStartTime(),queryDTO.getEndTime(),queryDTO.getUseType());
				change(result,signCount,durationTimeliness);
				result.setLabel(userService.getById(j).getRealName());
				result.setUserId(j);
				userList.add(result);
			});
		});
		CheckPlanUserCountVO resultVO = baseMapper.selectCheckPlanDeptCount(allUserIds,queryDTO);
		CheckPlanUserCountVO allSignCount = baseMapper.selectCheckPlanDeptSignCount(allUserIds,queryDTO);
		CheckPlanUserCountVO allDurationTimeliness = baseMapper.selectCheckPlanDeptDurationTimeliness(allUserIds,queryDTO);
		change(resultVO, allSignCount, allDurationTimeliness);
		resultVO.setLabel("全部");
		resultVO.setDeptList(deptList);
		resultVO.setUserList(userList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(CheckPlanUserCountVO::getUserId))),ArrayList::new)));
		return resultVO;
	}

	@Override
	public List<MaintainPlanUserDayCount> listAllByPlanner() {
		return baseMapper.listAllByPlanner();
	}

	@Override
	public CheckStatisticsWorkTimeDetailVO selectCheckWorkTimeDeptDetail(PlanCheckStatisticsQueryDTO queryDTO) {
		CheckStatisticsWorkTimeDetailVO statisticsDetailVO = baseMapper.selectCheckWorkTimeDeptDetail(queryDTO,queryDTO.getUserIds());
		if(statisticsDetailVO.getPlanTotal() != 0){
			statisticsDetailVO.setWorkTimeMinAve(statisticsDetailVO.getWorkTimeHour().divide(BigDecimal.valueOf(statisticsDetailVO.getPlanTotal()),1,RoundingMode.HALF_UP));
			statisticsDetailVO.setWorkTimeHour(statisticsDetailVO.getWorkTimeHour().divide(BigDecimal.valueOf(60),2,RoundingMode.HALF_UP));
		}else {
			statisticsDetailVO = new CheckStatisticsWorkTimeDetailVO();
		}
		return statisticsDetailVO;
	}

	@Override
	public List<CheckStatisticsWorkTimeCountVO> selectCheckWorkTimeDeptCount(PlanCheckStatisticsQueryDTO queryDTO) {
		List<Long> userIds = this.initDeptUserIds(queryDTO);
		List<CheckStatisticsWorkTimeCountVO> result = new ArrayList<>();
		List<MaintainSign> signList = signService.listByUserDate(queryDTO,userIds);
		if(ObjectUtil.isNotEmpty(signList)){
			queryDTO.getDeptGroups().forEach(e -> {
				CheckStatisticsWorkTimeCountVO countVO = new CheckStatisticsWorkTimeCountVO(e.getDeptName());

				// 组总人数
//				int userTotal = e.getUserIds().size();
				// 组总作业天数
//				long dayTotal = signList.stream().filter(k -> e.getUserIds().contains(k.getUserId())).map(j -> DateUtil.format(j.getCreateTime(),"yyyy-MM-dd")).distinct().count();

				// 组实际工作人数
				long userWork = signList.stream().map(MaintainSign::getUserId).filter(userId -> e.getUserIds().contains(userId)).distinct().count();
				countVO.setWorkPeo(userWork);

				// 组总工单数
				long planTotal = signList.stream().filter(k -> e.getUserIds().contains(k.getUserId())).map(MaintainSign::getPlanId).distinct().count();

				// 组总时长
				long timeInterval = signList.stream().filter(k -> e.getUserIds().contains(k.getUserId()) && ObjectUtil.isNotEmpty(k.getTimeInterval())).mapToLong(MaintainSign::getTimeInterval).sum();
				countVO.setWorkTimeHour(BigDecimal.valueOf(timeInterval).divide(BigDecimal.valueOf(60),2,RoundingMode.HALF_UP));

				if(planTotal != 0){
					// 组工单平均时长
					countVO.setWorkTimeMinAve(BigDecimal.valueOf(timeInterval).divide(BigDecimal.valueOf(planTotal),1,RoundingMode.HALF_UP));

					// 组人均每日作业时长
//					countVO.setDayWorkTimePeoAve(BigDecimal.valueOf(timeInterval).divide(BigDecimal.valueOf(dayTotal),3,RoundingMode.HALF_UP)
//						.divide(BigDecimal.valueOf(userTotal),3,RoundingMode.HALF_UP).divide(BigDecimal.valueOf(60),2,RoundingMode.HALF_UP));
				}

				result.add(countVO);
			});
		}else {
			queryDTO.getDeptGroups().forEach(e -> {
				CheckStatisticsWorkTimeCountVO countVO = new CheckStatisticsWorkTimeCountVO(e.getDeptName());
				result.add(countVO);
			});
		}
		return result;
	}

	@Override
	public List<CheckStatisticsWorkTimeCountVO> selectCheckWorkTimeDeptUserCount(PlanCheckStatisticsQueryDTO queryDTO) {
		List<User> users = userService.listByIds(queryDTO.getUserIds());
		List<CheckStatisticsWorkTimeCountVO> result = new ArrayList<>();
		List<MaintainSign> signList = signService.listByUserDate(queryDTO,queryDTO.getUserIds());
		if(ObjectUtil.isNotEmpty(signList)){
			Map<String,List<MaintainSign>> userSignMap = signList.stream().collect(Collectors.groupingBy(MaintainSign::getUserName));

			// 人总工单数
			long totalPlanTotal = signList.stream().map(MaintainSign::getPlanId).distinct().count();
			// 人总作业天数
			long totalDayTotal = signList.stream().map(j -> DateUtil.format(j.getCreateTime(),"yyyy-MM-dd")).distinct().count();
			// 人总时长
			AtomicLong totalTimeInterval = new AtomicLong(0L);

			users.forEach(e -> {
				CheckStatisticsWorkTimeCountVO countVO = new CheckStatisticsWorkTimeCountVO(e.getRealName());

				List<MaintainSign> userSignList = userSignMap.get(e.getRealName());
				if(ObjectUtil.isNotEmpty(userSignList)){

					// 每人总工单数
					long planTotal = userSignList.stream().map(MaintainSign::getPlanId).distinct().count();
					// 每人总作业天数
					long dayTotal = userSignList.stream().map(j -> DateUtil.format(j.getCreateTime(),"yyyy-MM-dd")).distinct().count();
					countVO.setDayWork(dayTotal);

					// 每人总时长
					long timeInterval = userSignList.stream().filter(k -> ObjectUtil.isNotEmpty(k.getTimeInterval())).mapToLong(MaintainSign::getTimeInterval).sum();
					countVO.setWorkTimeHour(BigDecimal.valueOf(timeInterval).divide(BigDecimal.valueOf(60),2,RoundingMode.HALF_UP));
					totalTimeInterval.addAndGet(timeInterval);

					if(planTotal != 0){
						// 每人工单平均时长
						countVO.setWorkTimeMinAve(BigDecimal.valueOf(timeInterval).divide(BigDecimal.valueOf(planTotal),1,RoundingMode.HALF_UP));
					}
				}
				result.add(countVO);
			});

			CheckStatisticsWorkTimeCountVO totalVO = new CheckStatisticsWorkTimeCountVO("全部");
			if(totalPlanTotal != 0){
				// 总时长
				totalVO.setWorkTimeHour(BigDecimal.valueOf(totalTimeInterval.get()).divide(BigDecimal.valueOf(60),2,RoundingMode.HALF_UP));
				// 人工单平均时长
				totalVO.setWorkTimeMinAve(BigDecimal.valueOf(totalTimeInterval.get()).divide(BigDecimal.valueOf(totalPlanTotal),1,RoundingMode.HALF_UP));
				// 总天数
				totalVO.setDayWork(totalDayTotal);
			}
			result.add(0,totalVO);
		}else {
			CheckStatisticsWorkTimeCountVO totalVO = new CheckStatisticsWorkTimeCountVO("全部");
			result.add(totalVO);
			users.forEach(e -> {
				CheckStatisticsWorkTimeCountVO countVO = new CheckStatisticsWorkTimeCountVO(e.getRealName());
				result.add(countVO);
			});
		}
		return result;
	}

	@Override
	public CheckStatisticsStatusDetailVO selectCheckStatusDeptDetail(PlanCheckStatisticsQueryDTO queryDTO) {
		List<Long> userIds = queryDTO.getUserIds();
		List<MaintainPlanContent> planContents = planContentService.listByUserDate(queryDTO,userIds);
		CheckStatisticsStatusDetailVO detailVO = new CheckStatisticsStatusDetailVO();

		if(ObjectUtil.isNotEmpty(planContents)){
			// 总工单数
			long planTotal = planContents.stream().map(MaintainPlanContent::getId).distinct().count();
			detailVO.setPlanTotal(planTotal);
			// 未执行
			long toStart = planContents.stream().filter(e -> e.getStatus().equals(TaskStatusEnum.BY_DISABLE.getStatus())).map(MaintainPlanContent::getId).distinct().count();
			// 进行中
			long underway = planContents.stream().filter(e -> e.getStatus().equals(TaskStatusEnum.BY_PROCESSED.getStatus())).map(MaintainPlanContent::getId).distinct().count();
			// 已提交
			long commit = planContents.stream().filter(e -> e.getStatus().equals(TaskStatusEnum.BY_FINISH.getStatus())).map(MaintainPlanContent::getId).distinct().count();
			// 已完成
			long finished = planContents.stream().filter(e -> e.getStatus().equals(TaskStatusEnum.BY_SIGN.getStatus())).map(MaintainPlanContent::getId).distinct().count();
			// 维保签字
			long maintainSignature = planContents.stream().filter(e -> e.getStatus().equals(TaskStatusEnum.BY_MAINTAIN_SIGN.getStatus())).map(MaintainPlanContent::getId).distinct().count();
			if(planTotal != 0){
				detailVO.setToStartPer(BigDecimal.valueOf(toStart).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				detailVO.setUnderwayPer(BigDecimal.valueOf(underway).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				detailVO.setCommitPer(BigDecimal.valueOf(commit).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				detailVO.setFinishedPer(BigDecimal.valueOf(finished).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				detailVO.setMaintainSignaturePer(BigDecimal.valueOf(maintainSignature).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
			}
		}
		return detailVO;
	}

	@Override
	public List<CheckStatisticsStatusCountVO> selectCheckStatusDeptCount(PlanCheckStatisticsQueryDTO queryDTO) {
		List<Long> userIds = this.initDeptUserIds(queryDTO);
		List<MaintainPlanContent> planContents = planContentService.listByUserDate(queryDTO,userIds);
		List<CheckStatisticsStatusCountVO> result = new ArrayList<>();
		if(ObjectUtil.isNotEmpty(planContents)){
			queryDTO.getDeptGroups().forEach(e -> {
				CheckStatisticsStatusCountVO countVO = new CheckStatisticsStatusCountVO(e.getDeptName());
				// 总工单数
				long planTotal = planContents.stream().filter(k -> e.getUserIds().contains(k.getUserId())).map(MaintainPlanContent::getId).distinct().count();
				// 未执行
				long toStart = planContents.stream().filter(k -> e.getUserIds().contains(k.getUserId()) && k.getStatus().equals(TaskStatusEnum.BY_DISABLE.getStatus())).map(MaintainPlanContent::getId).distinct().count();
				countVO.setToStart(toStart);
				// 进行中
				long underway = planContents.stream().filter(k -> e.getUserIds().contains(k.getUserId()) && k.getStatus().equals(TaskStatusEnum.BY_PROCESSED.getStatus())).map(MaintainPlanContent::getId).distinct().count();
				countVO.setUnderway(underway);
				// 已提交
				long commit = planContents.stream().filter(k -> e.getUserIds().contains(k.getUserId()) && k.getStatus().equals(TaskStatusEnum.BY_FINISH.getStatus())).map(MaintainPlanContent::getId).distinct().count();
				countVO.setCommit(commit);
				// 已完成
				long finished = planContents.stream().filter(k -> e.getUserIds().contains(k.getUserId()) && k.getStatus().equals(TaskStatusEnum.BY_SIGN.getStatus())).map(MaintainPlanContent::getId).distinct().count();
				countVO.setFinished(finished);
				// 已完成
				long maintainSignature = planContents.stream().filter(k -> e.getUserIds().contains(k.getUserId()) && k.getStatus().equals(TaskStatusEnum.BY_MAINTAIN_SIGN.getStatus())).map(MaintainPlanContent::getId).distinct().count();
				countVO.setMaintainSignature(maintainSignature);
				if(planTotal != 0){
					countVO.setToStartPer(BigDecimal.valueOf(toStart).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
					countVO.setUnderwayPer(BigDecimal.valueOf(underway).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
					countVO.setCommitPer(BigDecimal.valueOf(commit).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
					countVO.setFinishedPer(BigDecimal.valueOf(finished).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
					countVO.setMaintainSignaturePer(BigDecimal.valueOf(maintainSignature).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				}
				result.add(countVO);
			});
		}else {
			queryDTO.getDeptGroups().forEach(e -> {
				CheckStatisticsStatusCountVO countVO = new CheckStatisticsStatusCountVO(e.getDeptName());
				result.add(countVO);
			});
		}
		return result;
	}

	@Override
	public List<CheckStatisticsStatusCountVO> selectCheckStatusDeptUserCount(PlanCheckStatisticsQueryDTO queryDTO) {
		List<User> users = userService.listByIds(queryDTO.getUserIds());
		List<MaintainPlanContent> planContents = planContentService.listByUserDate(queryDTO,queryDTO.getUserIds());
		List<CheckStatisticsStatusCountVO> result = new ArrayList<>();
		if(ObjectUtil.isNotEmpty(planContents)){
			// 总工单数
			long totalPlanTotal = planContents.stream().map(MaintainPlanContent::getId).distinct().count();
			// 未执行
			long totalToStart = planContents.stream().filter(k -> k.getStatus().equals(TaskStatusEnum.BY_DISABLE.getStatus())).map(MaintainPlanContent::getId).distinct().count();
			// 进行中
			long totalUnderway = planContents.stream().filter(k -> k.getStatus().equals(TaskStatusEnum.BY_PROCESSED.getStatus())).map(MaintainPlanContent::getId).distinct().count();
			// 已提交
			long totalCommit = planContents.stream().filter(k -> k.getStatus().equals(TaskStatusEnum.BY_FINISH.getStatus())).map(MaintainPlanContent::getId).distinct().count();
			// 已完成
			long totalFinished = planContents.stream().filter(k -> k.getStatus().equals(TaskStatusEnum.BY_SIGN.getStatus())).map(MaintainPlanContent::getId).distinct().count();
			// 维保签字
			long totalMaintainSignature = planContents.stream().filter(k -> k.getStatus().equals(TaskStatusEnum.BY_MAINTAIN_SIGN.getStatus())).map(MaintainPlanContent::getId).distinct().count();
			users.forEach(e -> {

				CheckStatisticsStatusCountVO countVO = new CheckStatisticsStatusCountVO(e.getRealName());
				// 总工单数
				long planTotal = planContents.stream().filter(k -> e.getId().equals(k.getUserId())).map(MaintainPlanContent::getId).distinct().count();
				// 未执行
				long toStart = planContents.stream().filter(k -> e.getId().equals(k.getUserId()) && k.getStatus().equals(TaskStatusEnum.BY_DISABLE.getStatus())).map(MaintainPlanContent::getId).distinct().count();
				countVO.setToStart(toStart);
				// 进行中
				long underway = planContents.stream().filter(k -> e.getId().equals(k.getUserId()) && k.getStatus().equals(TaskStatusEnum.BY_PROCESSED.getStatus())).map(MaintainPlanContent::getId).distinct().count();
				countVO.setUnderway(underway);
				// 已提交
				long commit = planContents.stream().filter(k -> e.getId().equals(k.getUserId()) && k.getStatus().equals(TaskStatusEnum.BY_FINISH.getStatus())).map(MaintainPlanContent::getId).distinct().count();
				countVO.setCommit(commit);
				// 已完成
				long finished = planContents.stream().filter(k -> e.getId().equals(k.getUserId()) && k.getStatus().equals(TaskStatusEnum.BY_SIGN.getStatus())).map(MaintainPlanContent::getId).distinct().count();
				countVO.setFinished(finished);
				// 维保签字
				long maintainSignature = planContents.stream().filter(k -> e.getId().equals(k.getUserId()) && k.getStatus().equals(TaskStatusEnum.BY_MAINTAIN_SIGN.getStatus())).map(MaintainPlanContent::getId).distinct().count();
				countVO.setMaintainSignature(maintainSignature);
				if(planTotal != 0){
					countVO.setToStartPer(BigDecimal.valueOf(toStart).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
					countVO.setUnderwayPer(BigDecimal.valueOf(underway).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
					countVO.setCommitPer(BigDecimal.valueOf(commit).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
					countVO.setFinishedPer(BigDecimal.valueOf(finished).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
					countVO.setMaintainSignaturePer(BigDecimal.valueOf(maintainSignature).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				}
				result.add(countVO);

			});

			CheckStatisticsStatusCountVO totalVO = new CheckStatisticsStatusCountVO("全部");
			if(totalPlanTotal != 0){
				totalVO.setToStart(totalToStart);
				totalVO.setUnderway(totalUnderway);
				totalVO.setCommit(totalCommit);
				totalVO.setFinished(totalFinished);
				totalVO.setMaintainSignature(totalMaintainSignature);
				totalVO.setToStartPer(BigDecimal.valueOf(totalToStart).divide(BigDecimal.valueOf(totalPlanTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				totalVO.setUnderwayPer(BigDecimal.valueOf(totalUnderway).divide(BigDecimal.valueOf(totalPlanTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				totalVO.setCommitPer(BigDecimal.valueOf(totalCommit).divide(BigDecimal.valueOf(totalPlanTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				totalVO.setFinishedPer(BigDecimal.valueOf(totalFinished).divide(BigDecimal.valueOf(totalPlanTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				totalVO.setMaintainSignaturePer(BigDecimal.valueOf(totalMaintainSignature).divide(BigDecimal.valueOf(totalPlanTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
			}
			result.add(0,totalVO);
		}else {
			CheckStatisticsStatusCountVO totalVO = new CheckStatisticsStatusCountVO("全部");
			result.add(totalVO);
			users.forEach(e -> {
				CheckStatisticsStatusCountVO countVO = new CheckStatisticsStatusCountVO(e.getRealName());
				result.add(countVO);
			});
		}
		return result;
	}

	@Override
	public CheckStatisticsTimelinessDetailVO selectCheckTimelinessDeptDetail(PlanCheckStatisticsQueryDTO queryDTO) {
		List<Long> userIds = queryDTO.getUserIds();
		List<CheckStatisticsPlanSimpleDTO> planContentExts = planContentService.listPlanExtByUserDate(queryDTO,userIds);
		CheckStatisticsTimelinessDetailVO result = new CheckStatisticsTimelinessDetailVO();

		if(ObjectUtil.isNotEmpty(planContentExts)){
			// 工单总数
			long planTotal = planContentExts.stream().map(CheckStatisticsPlanSimpleDTO::getPlanId).distinct().count();
			result.setPlanTotal(planTotal);
			if(planTotal != 0){
				// 及时率
				long inTime = planContentExts.stream()
					.filter(k -> (DateUtil.format(k.getPlanDate(),"yyyy-MM-dd").equals(DateUtil.format(DateUtil.date(),"yyyy-MM-dd"))
							&& k.getStatus().equals(TaskStatusEnum.BY_SIGN.getStatus())
						|| (!DateUtil.format(k.getPlanDate(),"yyyy-MM-dd").equals(DateUtil.format(DateUtil.date(),"yyyy-MM-dd"))
						&& ObjectUtil.isEmpty(k.getOverdueDay())))).map(CheckStatisticsPlanSimpleDTO::getPlanId).distinct().count();
				result.setInTimePer(BigDecimal.valueOf(inTime).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				// 逾期率
				long overdue = planContentExts.stream().filter(k ->
					!DateUtil.format(k.getPlanDate(), "yyyy-MM-dd").equals(DateUtil.format(DateUtil.date(), "yyyy-MM-dd")) && ObjectUtil.isNotEmpty(k.getOverdueDay()))
					.map(CheckStatisticsPlanSimpleDTO::getPlanId).distinct().count();
				result.setOverduePer(BigDecimal.valueOf(overdue).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				// 待定
				long undetermined = planContentExts.stream()
					.filter(k -> DateUtil.format(k.getPlanDate(),"yyyy-MM-dd").equals(DateUtil.format(DateUtil.date(),"yyyy-MM-dd"))
						&& !k.getStatus().equals(TaskStatusEnum.BY_SIGN.getStatus())).map(CheckStatisticsPlanSimpleDTO::getPlanId).distinct().count();
				result.setUndeterminedPer(BigDecimal.valueOf(undetermined).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
			}
		}
		return result;
	}

	@Override
	public List<CheckStatisticsTimelinessCountVO> selectCheckTimelinessDeptCount(PlanCheckStatisticsQueryDTO queryDTO) {
		List<Long> userIds = this.initDeptUserIds(queryDTO);
		List<CheckStatisticsPlanSimpleDTO> planContentExts = planContentService.listPlanExtByUserDate(queryDTO,userIds);
		List<CheckStatisticsTimelinessCountVO> result = new ArrayList<>();
		if(ObjectUtil.isNotEmpty(planContentExts)){
			queryDTO.getDeptGroups().forEach(e -> {
				CheckStatisticsTimelinessCountVO countVO = new CheckStatisticsTimelinessCountVO(e.getDeptName());
				// 工单总数
				long planTotal = planContentExts.stream().filter(k -> e.getUserIds().contains(k.getUserId())).map(CheckStatisticsPlanSimpleDTO::getPlanId).distinct().count();
				countVO.setPlanTotal(planTotal);
				if(planTotal != 0){

					List<CheckStatisticsPlanSimpleDTO> userPlanContentExts = planContentExts.stream().filter(k -> e.getUserIds().contains(k.getUserId())).collect(Collectors.toList());

					List<Long> inTimePlan = new ArrayList<>();
					List<Long> overduePlan = new ArrayList<>();
					List<Long> undeterminedPlan = new ArrayList<>();
					userPlanContentExts.forEach(k -> {
						if(ObjectUtil.isEmpty(k.getOverdueDay())){
							if(DateUtil.format(k.getPlanDate(),"yyyy-MM-dd").equals(DateUtil.format(DateUtil.date(),"yyyy-MM-dd"))){
								if(k.getStatus().equals(TaskStatusEnum.BY_SIGN.getStatus())){
									inTimePlan.add(k.getPlanId());
								}else {
									undeterminedPlan.add(k.getPlanId());
								}
							}else {
								inTimePlan.add(k.getPlanId());
							}
						}else{
							overduePlan.add(k.getPlanId());
						}
					});
					long inTime = inTimePlan.stream().distinct().count();
					long overdue = overduePlan.stream().distinct().count();
					long undetermined = undeterminedPlan.stream().distinct().count();
					countVO.setInTime(inTime);
					countVO.setOverdue(overdue);
					countVO.setUndetermined(undetermined);
					countVO.setInTimePer(BigDecimal.valueOf(inTime).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
					countVO.setOverduePer(BigDecimal.valueOf(overdue).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
					countVO.setUndeterminedPer(BigDecimal.valueOf(undetermined).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));

//					// 及时率
//					long inTime = userPlanContentExts.stream()
//						.filter(k -> ((DateUtil.format(k.getPlanDate(),"yyyy-MM-dd").equals(DateUtil.format(DateUtil.date(),"yyyy-MM-dd"))
//							&& k.getStatus().equals(TaskStatusEnum.BY_SIGN.getStatus())
//							|| ObjectUtil.isEmpty(k.getOverdueDay())))).map(CheckStatisticsPlanSimpleDTO::getPlanId).distinct().count();
//					countVO.setInTime(inTime);
//					countVO.setInTimePer(BigDecimal.valueOf(inTime).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
//					// 逾期率
//					long overdue = userPlanContentExts.stream().filter(k -> (!DateUtil.format(k.getPlanDate(), "yyyy-MM-dd").equals(DateUtil.format(DateUtil.date(), "yyyy-MM-dd")) && ObjectUtil.isNotEmpty(k.getOverdueDay())))
//						.map(CheckStatisticsPlanSimpleDTO::getPlanId).distinct().count();
//					countVO.setOverdue(overdue);
//					countVO.setOverduePer(BigDecimal.valueOf(overdue).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
//					// 待定
//					long undetermined = userPlanContentExts.stream()
//						.filter(k -> (DateUtil.format(k.getPlanDate(),"yyyy-MM-dd").equals(DateUtil.format(DateUtil.date(),"yyyy-MM-dd"))
//							&& !k.getStatus().equals(TaskStatusEnum.BY_SIGN.getStatus()))).map(CheckStatisticsPlanSimpleDTO::getPlanId).distinct().count();
//					countVO.setUndetermined(undetermined);
//					countVO.setUndeterminedPer(BigDecimal.valueOf(undetermined).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				}
				result.add(countVO);
			});
		}else{
			queryDTO.getDeptGroups().forEach(e -> {
				CheckStatisticsTimelinessCountVO countVO = new CheckStatisticsTimelinessCountVO(e.getDeptName());
				result.add(countVO);
			});
		}
		return result;
	}

	@Override
	public List<CheckStatisticsTimelinessCountVO> selectCheckTimelinessDeptUserCount(PlanCheckStatisticsQueryDTO queryDTO) {
		List<User> users = userService.listByIds(queryDTO.getUserIds());
		List<CheckStatisticsPlanSimpleDTO> planContentExts = planContentService.listPlanExtByUserDate(queryDTO,queryDTO.getUserIds());
		List<CheckStatisticsTimelinessCountVO> result = new ArrayList<>();
		if(ObjectUtil.isNotEmpty(planContentExts)){
			CheckStatisticsTimelinessCountVO totalVO = new CheckStatisticsTimelinessCountVO("全部");
			// 工单总数
			long totalPlanTotal = planContentExts.stream().map(CheckStatisticsPlanSimpleDTO::getPlanId).distinct().count();
			// 及时总数
			List<Long> totalInTime = new ArrayList<>();
			// 逾期总数
			List<Long> totalOverdue = new ArrayList<>();
			// 待定总数
			List<Long> totalUndetermined = new ArrayList<>();
			users.forEach(e -> {
				CheckStatisticsTimelinessCountVO countVO = new CheckStatisticsTimelinessCountVO(e.getRealName());
				// 工单总数
				long planTotal = planContentExts.stream().filter(k -> e.getId().equals(k.getUserId())).map(CheckStatisticsPlanSimpleDTO::getPlanId).distinct().count();
				countVO.setPlanTotal(planTotal);
				if(planTotal != 0){

					List<CheckStatisticsPlanSimpleDTO> userPlanContentExts = planContentExts.stream().filter(k -> e.getId().equals(k.getUserId())).collect(Collectors.toList());

					List<Long> inTimePlan = new ArrayList<>();
					List<Long> overduePlan = new ArrayList<>();
					List<Long> undeterminedPlan = new ArrayList<>();
					userPlanContentExts.forEach(k -> {
						if(ObjectUtil.isEmpty(k.getOverdueDay())){
							if(DateUtil.format(k.getPlanDate(),"yyyy-MM-dd").equals(DateUtil.format(DateUtil.date(),"yyyy-MM-dd"))){
								if(k.getStatus().equals(TaskStatusEnum.BY_SIGN.getStatus())){
									inTimePlan.add(k.getPlanId());
									totalInTime.add(k.getPlanId());
								}else {
									undeterminedPlan.add(k.getPlanId());
									totalUndetermined.add(k.getPlanId());
								}
							}else {
								inTimePlan.add(k.getPlanId());
								totalInTime.add(k.getPlanId());
							}
						}else{
							overduePlan.add(k.getPlanId());
							totalOverdue.add(k.getPlanId());
						}
					});
					long inTime = inTimePlan.stream().distinct().count();
					long overdue = overduePlan.stream().distinct().count();
					long undetermined = undeterminedPlan.stream().distinct().count();
					countVO.setInTime(inTime);
					countVO.setOverdue(overdue);
					countVO.setUndetermined(undetermined);
					countVO.setInTimePer(BigDecimal.valueOf(inTime).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
					countVO.setOverduePer(BigDecimal.valueOf(overdue).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
					countVO.setUndeterminedPer(BigDecimal.valueOf(undetermined).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));

//					// 及时率
//					long inTime = userPlanContentExts.stream()
//						.filter(k -> e.getId().equals(k.getUserId())
//							&& ((DateUtil.format(k.getPlanDate(),"yyyy-MM-dd").equals(DateUtil.format(DateUtil.date(),"yyyy-MM-dd"))
//							&& k.getStatus().equals(TaskStatusEnum.BY_SIGN.getStatus())
//							|| ObjectUtil.isEmpty(k.getOverdueDay())))).map(CheckStatisticsPlanSimpleDTO::getPlanId).distinct().count();
//					countVO.setInTime(inTime);
//					countVO.setInTimePer(BigDecimal.valueOf(inTime).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
//					// 逾期率
//					long overdue = userPlanContentExts.stream().filter(k -> e.getId().equals(k.getUserId())
//							&& (!DateUtil.format(k.getPlanDate(), "yyyy-MM-dd").equals(DateUtil.format(DateUtil.date(), "yyyy-MM-dd")) && ObjectUtil.isNotEmpty(k.getOverdueDay())))
//						.map(CheckStatisticsPlanSimpleDTO::getPlanId).distinct().count();
//					countVO.setOverdue(overdue);
//					countVO.setOverduePer(BigDecimal.valueOf(overdue).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
//					// 待定
//					long undetermined = userPlanContentExts.stream()
//						.filter(k -> (DateUtil.format(k.getPlanDate(),"yyyy-MM-dd").equals(DateUtil.format(DateUtil.date(),"yyyy-MM-dd"))
//							&& !k.getStatus().equals(TaskStatusEnum.BY_SIGN.getStatus()))).map(CheckStatisticsPlanSimpleDTO::getPlanId).distinct().count();
//					countVO.setUndetermined(undetermined);
//					countVO.setUndeterminedPer(BigDecimal.valueOf(undetermined).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				}
				result.add(countVO);
			});

			if(ObjectUtil.isNotEmpty(totalPlanTotal)){
				totalVO.setPlanTotal(totalPlanTotal);
				totalVO.setInTime(totalInTime.stream().distinct().count());
				totalVO.setOverdue(totalOverdue.stream().distinct().count());
				totalVO.setUndetermined(totalUndetermined.stream().distinct().count());
				totalVO.setInTimePer(BigDecimal.valueOf(totalVO.getInTime()).divide(BigDecimal.valueOf(totalPlanTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				totalVO.setOverduePer(BigDecimal.valueOf(totalVO.getOverdue()).divide(BigDecimal.valueOf(totalPlanTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				totalVO.setUndeterminedPer(BigDecimal.valueOf(totalVO.getUndetermined()).divide(BigDecimal.valueOf(totalPlanTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
			}
			result.add(0,totalVO);
		}else {
			CheckStatisticsTimelinessCountVO totalVO = new CheckStatisticsTimelinessCountVO("全部");
			result.add(totalVO);
			users.forEach(e -> {
				CheckStatisticsTimelinessCountVO countVO = new CheckStatisticsTimelinessCountVO(e.getRealName());
				result.add(countVO);
			});
		}
		return result;
	}

	@Override
	public CheckStatisticsDurationDetailVO selectCheckDurationDeptDetail(PlanCheckStatisticsQueryDTO queryDTO) {
		List<Long> userIds = queryDTO.getUserIds();
		List<MaintainSign> signList = signService.listCommitByUserDate(queryDTO,userIds);
		CheckStatisticsDurationDetailVO result = new CheckStatisticsDurationDetailVO();
		if(ObjectUtil.isNotEmpty(signList)){
			// 总工单数
			long planTotal = signList.stream().map(MaintainSign::getPlanId).distinct().count();
			result.setPlanTotal(planTotal);
			if(planTotal != 0){
				// 工单分组
				Map<Long,List<MaintainSign>> planGroup = signList.stream().collect(Collectors.groupingBy(MaintainSign::getPlanId));
				AtomicLong normal = new AtomicLong(0);
				AtomicLong toLong = new AtomicLong(0);
				AtomicLong toShoot = new AtomicLong(0);
				planGroup.forEach((k,v) -> {
					long timeInterval = v.stream().mapToLong(MaintainSign::getTimeInterval).sum();
					if(timeInterval > 60) {
						toLong.incrementAndGet();
					}else if(timeInterval < 25) {
						toShoot.incrementAndGet();
					}else {
						normal.incrementAndGet();
					}
				});
				result.setNormalPer(BigDecimal.valueOf(normal.get()).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				result.setToLongPer(BigDecimal.valueOf(toLong.get()).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				result.setToShootPer(BigDecimal.valueOf(toShoot.get()).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
			}
		}
		return result;
	}

	@Override
	public List<CheckStatisticsDurationCountVO> selectCheckDurationDeptCount(PlanCheckStatisticsQueryDTO queryDTO) {
		List<Long> userIds = this.initDeptUserIds(queryDTO);
		List<MaintainSign> signList = signService.listCommitByUserDate(queryDTO,userIds);
		List<CheckStatisticsDurationCountVO> result = new ArrayList<>();
		if(ObjectUtil.isNotEmpty(signList)){
			queryDTO.getDeptGroups().forEach(e -> {
				CheckStatisticsDurationCountVO countVO = new CheckStatisticsDurationCountVO(e.getDeptName());

				// 工单分组
				Map<Long,List<MaintainSign>> planGroup = signList.stream().collect(Collectors.groupingBy(MaintainSign::getPlanId));
				List<Long> deptPlanIds = signList.stream().filter(k -> e.getUserIds().contains(k.getUserId())).map(MaintainSign::getPlanId).distinct().collect(Collectors.toList());
				long planTotal = deptPlanIds.size();
				if(planTotal != 0){
					AtomicLong normal = new AtomicLong(0);
					AtomicLong toLong = new AtomicLong(0);
					AtomicLong toShoot = new AtomicLong(0);
					deptPlanIds.forEach(k -> {
						long timeInterval = planGroup.get(k).stream().mapToLong(MaintainSign::getTimeInterval).sum();
						if(timeInterval > 60) {
							toLong.incrementAndGet();
						}else if(timeInterval < 25) {
							toShoot.incrementAndGet();
						}else {
							normal.incrementAndGet();
						}
					});
					countVO.setNormal(normal.get());
					countVO.setToLong(toLong.get());
					countVO.setToShoot(toShoot.get());
					countVO.setNormalPer(BigDecimal.valueOf(normal.get()).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
					countVO.setToLongPer(BigDecimal.valueOf(toLong.get()).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
					countVO.setToShootPer(BigDecimal.valueOf(toShoot.get()).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				}
				result.add(countVO);
			});
		}else {
			queryDTO.getDeptGroups().forEach(e -> {
				CheckStatisticsDurationCountVO countVO = new CheckStatisticsDurationCountVO(e.getDeptName());
				result.add(countVO);
			});
		}
		return result;
	}

	@Override
	public List<CheckStatisticsDurationCountVO> selectCheckDurationDeptUserCount(PlanCheckStatisticsQueryDTO queryDTO) {
		List<User> users = userService.listByIds(queryDTO.getUserIds());
		List<MaintainSign> signList = signService.listCommitByUserDate(queryDTO,queryDTO.getUserIds());
		List<CheckStatisticsDurationCountVO> result = new ArrayList<>();
		if(ObjectUtil.isNotEmpty(signList)){
			// 工单分组
			Map<Long,List<MaintainSign>> planGroup = signList.stream().collect(Collectors.groupingBy(MaintainSign::getPlanId));
			CheckStatisticsDurationCountVO totalVO = new CheckStatisticsDurationCountVO("全部");
			long totalPlanTotal = signList.stream().map(MaintainSign::getPlanId).distinct().count();
			long totalNormal = planGroup.entrySet().stream().filter(k -> k.getValue().stream().mapToLong(MaintainSign::getTimeInterval).sum() >= 25
				&& k.getValue().stream().mapToLong(MaintainSign::getTimeInterval).sum() <= 60).count();
			long totalToLong = planGroup.entrySet().stream().filter(k -> k.getValue().stream().mapToLong(MaintainSign::getTimeInterval).sum() > 60).count();
			long totalToShoot = planGroup.entrySet().stream().filter(k -> k.getValue().stream().mapToLong(MaintainSign::getTimeInterval).sum() < 25).count();
			users.forEach(e -> {
				CheckStatisticsDurationCountVO countVO = new CheckStatisticsDurationCountVO(e.getRealName());

				List<Long> deptPlanIds = signList.stream().filter(k -> e.getId().equals(k.getUserId())).map(MaintainSign::getPlanId).distinct().collect(Collectors.toList());
				long planTotal = deptPlanIds.size();
				if(planTotal != 0){
					AtomicLong normal = new AtomicLong(0);
					AtomicLong toLong = new AtomicLong(0);
					AtomicLong toShoot = new AtomicLong(0);
					deptPlanIds.forEach(k -> {
						long timeInterval = planGroup.get(k).stream().mapToLong(MaintainSign::getTimeInterval).sum();
						if(timeInterval > 60) {
							toLong.incrementAndGet();
						}else if(timeInterval < 25) {
							toShoot.incrementAndGet();
						}else {
							normal.incrementAndGet();
						}
					});
					countVO.setNormal(normal.get());
					countVO.setToLong(toLong.get());
					countVO.setToShoot(toShoot.get());
					countVO.setNormalPer(BigDecimal.valueOf(normal.get()).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
					countVO.setToLongPer(BigDecimal.valueOf(toLong.get()).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
					countVO.setToShootPer(BigDecimal.valueOf(toShoot.get()).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				}
				result.add(countVO);
			});
			totalVO.setPlanTotal(totalPlanTotal);
			totalVO.setNormal(totalNormal);
			totalVO.setToLong(totalToLong);
			totalVO.setToShoot(totalToShoot);
			totalVO.setNormalPer(BigDecimal.valueOf(totalNormal).divide(BigDecimal.valueOf(totalPlanTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
			totalVO.setToLongPer(BigDecimal.valueOf(totalToLong).divide(BigDecimal.valueOf(totalPlanTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
			totalVO.setToShootPer(BigDecimal.valueOf(totalToShoot).divide(BigDecimal.valueOf(totalPlanTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
			result.add(0,totalVO);
		}else {
			users.forEach(e -> {
				CheckStatisticsDurationCountVO countVO = new CheckStatisticsDurationCountVO(e.getRealName());
				result.add(countVO);
			});
		}
		return result;
	}

	@Override
	public CheckStatisticsSignDetailVO selectCheckSignDeptDetail(PlanCheckStatisticsQueryDTO queryDTO) {
		List<Long> userIds = queryDTO.getUserIds();
		List<MaintainSign> signList = signService.listByUserDate(queryDTO,userIds);
		CheckStatisticsSignDetailVO result = new CheckStatisticsSignDetailVO();
		if(ObjectUtil.isNotEmpty(signList)){
			// 总签到次数
			long signCount = signList.stream().filter(k -> ObjectUtil.isNotEmpty(k.getSignTime())).count();
			// 总签退次数
			long signOutCount = signList.stream().filter(k -> ObjectUtil.isNotEmpty(k.getSignOutTime())).count();
			// 总次数
			long signTotal = signCount + signOutCount;
			// 正常次数
			long signNormal = signList.stream().filter(k -> k.getSignStatus() == 1).count();
			long signOutNormal = signList.stream().filter(k -> ObjectUtil.isNotEmpty(k.getSignOutStatus()) && k.getSignOutStatus() == 1).count();
			signNormal = signNormal + signOutNormal;
			// 系统签退次数
			long systemSign = signList.stream().filter(k -> k.getStatus() == 2).count();
			// 签到异常
			long signError = signList.stream().filter(k -> k.getSignStatus() == 2).count();
			// 签退异常
			long signOutError = signList.stream().filter(k -> ObjectUtil.isNotEmpty(k.getSignOutStatus()) && k.getSignOutStatus() == 2).count();
			result.setSignTotal(signTotal);
			result.setSignNormalPer(BigDecimal.valueOf(signNormal).divide(BigDecimal.valueOf(signTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
			result.setSystemSignPer(BigDecimal.valueOf(systemSign).divide(BigDecimal.valueOf(signTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
			result.setSignErrorPer(BigDecimal.valueOf(signError).divide(BigDecimal.valueOf(signTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
			result.setSignOutErrorPer(BigDecimal.valueOf(signOutError).divide(BigDecimal.valueOf(signTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
		}
		return result;
	}

	@Override
	public List<CheckStatisticsSignCountVO> selectCheckSignDeptCount(PlanCheckStatisticsQueryDTO queryDTO) {
		List<Long> userIds = this.initDeptUserIds(queryDTO);
		List<MaintainSign> signList = signService.listByUserDate(queryDTO,userIds);
		List<CheckStatisticsSignCountVO> result = new ArrayList<>();
		if(ObjectUtil.isNotEmpty(signList)){
			queryDTO.getDeptGroups().forEach(e -> {

				CheckStatisticsSignCountVO countVO = new CheckStatisticsSignCountVO(e.getDeptName());
				List<MaintainSign> deptSignList = signList.stream().filter(k -> e.getUserIds().contains(k.getUserId())).collect(Collectors.toList());
				if(ObjectUtil.isNotEmpty(deptSignList)){
					// 总签到次数
					long signCount = deptSignList.stream().filter(k -> ObjectUtil.isNotEmpty(k.getSignTime())).count();
					// 总签退次数
					long signOutCount = deptSignList.stream().filter(k -> ObjectUtil.isNotEmpty(k.getSignOutTime())).count();
					// 总次数
					long signTotal = signCount + signOutCount;
					// 正常次数
					long signNormal = deptSignList.stream().filter(k -> k.getSignStatus() == 1).count();
					long signOutNormal = deptSignList.stream().filter(k -> ObjectUtil.isNotEmpty(k.getSignOutStatus()) && k.getSignOutStatus() == 1).count();
					signNormal = signNormal + signOutNormal;
					// 系统签退次数
					long systemSign = deptSignList.stream().filter(k -> k.getStatus() == 2).count();
					// 签到异常
					long signError = deptSignList.stream().filter(k -> k.getSignStatus() == 2).count();
					// 签退异常
					long signOutError = deptSignList.stream().filter(k -> ObjectUtil.isNotEmpty(k.getSignOutStatus()) && k.getSignOutStatus() == 2).count();
					countVO.setSignTotal(signTotal);
					countVO.setSignNormal(signNormal);
					countVO.setSystemSign(systemSign);
					countVO.setSignError(signError);
					countVO.setSignOutError(signOutError);
					countVO.setSignNormalPer(BigDecimal.valueOf(signNormal).divide(BigDecimal.valueOf(signTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
					countVO.setSystemSignPer(BigDecimal.valueOf(systemSign).divide(BigDecimal.valueOf(signTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
					countVO.setSignErrorPer(BigDecimal.valueOf(signError).divide(BigDecimal.valueOf(signTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
					countVO.setSignOutErrorPer(BigDecimal.valueOf(signOutError).divide(BigDecimal.valueOf(signTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				}

				result.add(countVO);
			});
		}else {
			queryDTO.getDeptGroups().forEach(e -> {
				CheckStatisticsSignCountVO countVO = new CheckStatisticsSignCountVO(e.getDeptName());
				result.add(countVO);
			});
		}
		return result;
	}

	@Override
	public List<CheckStatisticsSignCountVO> selectCheckSignDeptUserCount(PlanCheckStatisticsQueryDTO queryDTO) {
		List<User> users = userService.listByIds(queryDTO.getUserIds());
		List<MaintainSign> signList = signService.listByUserDate(queryDTO,queryDTO.getUserIds());
		List<CheckStatisticsSignCountVO> result = new ArrayList<>();
		if(ObjectUtil.isNotEmpty(signList)){
			CheckStatisticsSignCountVO totalVO = new CheckStatisticsSignCountVO("全部");
			AtomicLong totalSignTotal = new AtomicLong(0);
			AtomicLong totalSignNormal = new AtomicLong(0);
			AtomicLong totalSystemSign = new AtomicLong(0);
			AtomicLong totalSignError = new AtomicLong(0);
			AtomicLong totalSignOutError = new AtomicLong(0);
			users.forEach(e -> {
				CheckStatisticsSignCountVO countVO = new CheckStatisticsSignCountVO(e.getRealName());
				List<MaintainSign> deptSignList = signList.stream().filter(k -> e.getId().equals(k.getUserId())).collect(Collectors.toList());
				if(ObjectUtil.isNotEmpty(deptSignList)){
					// 总签到次数
					long signCount = deptSignList.stream().filter(k -> ObjectUtil.isNotEmpty(k.getSignTime())).count();
					// 总签退次数
					long signOutCount = deptSignList.stream().filter(k -> ObjectUtil.isNotEmpty(k.getSignOutTime())).count();
					// 总次数
					long signTotal = signCount + signOutCount;
					// 正常次数
					long signNormal = deptSignList.stream().filter(k -> k.getSignStatus() == 1).count();
					long signOutNormal = deptSignList.stream().filter(k -> ObjectUtil.isNotEmpty(k.getSignOutStatus()) && k.getSignOutStatus() == 1).count();
					signNormal = signNormal + signOutNormal;
					// 系统签退次数
					long systemSign = deptSignList.stream().filter(k -> k.getStatus() == 2).count();
					// 签到异常
					long signError = deptSignList.stream().filter(k -> k.getSignStatus() == 2).count();
					// 签退异常
					long signOutError = deptSignList.stream().filter(k -> ObjectUtil.isNotEmpty(k.getSignOutStatus()) && k.getSignOutStatus() == 2).count();
					countVO.setSignTotal(signTotal);
					countVO.setSignNormal(signNormal);
					countVO.setSystemSign(systemSign);
					countVO.setSignError(signError);
					countVO.setSignOutError(signOutError);
					countVO.setSignNormalPer(BigDecimal.valueOf(signNormal).divide(BigDecimal.valueOf(signTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
					countVO.setSystemSignPer(BigDecimal.valueOf(systemSign).divide(BigDecimal.valueOf(signTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
					countVO.setSignErrorPer(BigDecimal.valueOf(signError).divide(BigDecimal.valueOf(signTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
					countVO.setSignOutErrorPer(BigDecimal.valueOf(signOutError).divide(BigDecimal.valueOf(signTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
					totalSignTotal.addAndGet(signTotal);
					totalSignNormal.addAndGet(signNormal);
					totalSystemSign.addAndGet(systemSign);
					totalSignError.addAndGet(signError);
					totalSignOutError.addAndGet(signOutError);
				}
				result.add(countVO);
			});
			if(ObjectUtil.isNotEmpty(totalSignTotal.get())){
				totalVO.setSignTotal(totalSignTotal.get());
				totalVO.setSignNormal(totalSignNormal.get());
				totalVO.setSystemSign(totalSystemSign.get());
				totalVO.setSignError(totalSignError.get());
				totalVO.setSignOutError(totalSignOutError.get());
				totalVO.setSignNormalPer(BigDecimal.valueOf(totalSignNormal.get()).divide(BigDecimal.valueOf(totalSignTotal.get()),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				totalVO.setSystemSignPer(BigDecimal.valueOf(totalSystemSign.get()).divide(BigDecimal.valueOf(totalSignTotal.get()),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				totalVO.setSignErrorPer(BigDecimal.valueOf(totalSignError.get()).divide(BigDecimal.valueOf(totalSignTotal.get()),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				totalVO.setSignOutErrorPer(BigDecimal.valueOf(totalSignOutError.get()).divide(BigDecimal.valueOf(totalSignTotal.get()),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
			}
			result.add(0,totalVO);
		}else {
			CheckStatisticsSignCountVO totalVO = new CheckStatisticsSignCountVO("全部");
			result.add(totalVO);
			users.forEach(e -> {
				CheckStatisticsSignCountVO countVO = new CheckStatisticsSignCountVO(e.getRealName());
				result.add(countVO);
			});
		}
		return result;
	}

	@Override
	public List<CheckStatisticsTrendVO> selectCheckTrendEntiretyWorkTime(PlanCheckStatisticsQueryDTO queryDTO) {

		String[] initTypeArr = {"累计作业人工时","工单平均作业人工时"};
		List<CheckStatisticsTrendVO> result = this.initTrendEntirety(queryDTO,initTypeArr);
		List<MaintainPlanUserDayCount> planUserDayCounts = baseMapper.selectByUserDate(queryDTO);
		if(ObjectUtil.isNotEmpty(planUserDayCounts)){
			Map<String,List<MaintainPlanUserDayCount>> dateGroup;
			if(queryDTO.getDataType().equals(1)){
				// 日
				dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getRecordDate(),"yyyy/M/d")));
			}else if(queryDTO.getDataType().equals(2)){
				// 周
				dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> String.format("%s~%s",DateUtil.format(DateUtil.beginOfWeek(t.getRecordDate()), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(t.getRecordDate()), "yyyy/M/d"))));
			}else {
				// 月
				dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> String.format("%s月",DateUtil.format(t.getRecordDate(), "yyyy年M"))));
			}
			result.forEach(e -> dateGroup.forEach((k, v) -> {
				if(e.getType().equals(initTypeArr[0])){
					// 当天总时长
					long workTime = v.stream().mapToLong(MaintainPlanUserDayCount::getWorkTime).sum();
					e.getTrendData().put(k,BigDecimal.valueOf(workTime).divide(BigDecimal.valueOf(60),2,RoundingMode.HALF_UP));
				}else {
					// 当前总工单数
					long planTotal = v.stream().map(MaintainPlanUserDayCount::getPlanId).distinct().count();
					// 当天总时长
					long workTime = v.stream().mapToLong(MaintainPlanUserDayCount::getWorkTime).sum();
					e.getTrendData().put(k,BigDecimal.valueOf(workTime).divide(BigDecimal.valueOf(planTotal),1,RoundingMode.HALF_UP));
				}
			}));
		}
		return result;
	}

	@Override
	public List<CheckStatisticsTrendVO> selectCheckTrendEntiretyStatus(PlanCheckStatisticsQueryDTO queryDTO) {
		String[] initTypeArr = {"待开始","进行中","提交任务","维保签字","已完成"};
		List<CheckStatisticsTrendVO> result = this.initTrendEntirety(queryDTO,initTypeArr);
		List<MaintainPlanUserDayCount> planUserDayCounts = baseMapper.selectPlanStatusByUserDate(queryDTO);
		if(ObjectUtil.isNotEmpty(planUserDayCounts)){
			Map<String,List<MaintainPlanUserDayCount>> dateGroup;
			if(queryDTO.getDataType().equals(1)){
				// 日
				dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getPlanDate(),"yyyy/M/d")));
			}else if(queryDTO.getDataType().equals(2)){
				// 周
				dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> String.format("%s~%s",DateUtil.format(DateUtil.beginOfWeek(t.getPlanDate()), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(t.getPlanDate()), "yyyy/M/d"))));
			}else {
				// 月
				dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> String.format("%s月",DateUtil.format(t.getPlanDate(), "yyyy年M"))));
			}
			result.forEach(e -> dateGroup.forEach((k, v) -> {

				// 工单数量
				long planNum = 0L;
				if(e.getType().equals(initTypeArr[0])){
					planNum = v.stream().filter(t -> t.getPlanStatus().equals(TaskStatusEnum.BY_DISABLE.getStatus())).map(MaintainPlanUserDayCount::getPlanId).distinct().count();
				}else if(e.getType().equals(initTypeArr[1])) {
					planNum = v.stream().filter(t -> t.getPlanStatus().equals(TaskStatusEnum.BY_PROCESSED.getStatus())).map(MaintainPlanUserDayCount::getPlanId).distinct().count();
				}else if(e.getType().equals(initTypeArr[2])) {
					planNum = v.stream().filter(t -> t.getPlanStatus().equals(TaskStatusEnum.BY_FINISH.getStatus())).map(MaintainPlanUserDayCount::getPlanId).distinct().count();
				}else if(e.getType().equals(initTypeArr[3])) {
					planNum = v.stream().filter(t -> t.getPlanStatus().equals(TaskStatusEnum.BY_MAINTAIN_SIGN.getStatus())).map(MaintainPlanUserDayCount::getPlanId).distinct().count();
				}else if(e.getType().equals(initTypeArr[4])) {
					planNum = v.stream().filter(t -> t.getPlanStatus().equals(TaskStatusEnum.BY_SIGN.getStatus())).map(MaintainPlanUserDayCount::getPlanId).distinct().count();
				}
				e.getTrendData().put(k,BigDecimal.valueOf(planNum));
			}));
		}
		return result;
	}

	@Override
	public List<CheckStatisticsTrendVO> selectCheckTrendEntiretyTimeliness(PlanCheckStatisticsQueryDTO queryDTO) {
		String[] initTypeArr = {"及时","超时"};
		List<CheckStatisticsTrendVO> result = this.initTrendEntirety(queryDTO,initTypeArr);
		List<MaintainPlanUserDayCount> planUserDayCounts = baseMapper.selectPlanTimelinessByUserDate(queryDTO);
		if(ObjectUtil.isNotEmpty(planUserDayCounts)){
			Map<String,List<MaintainPlanUserDayCount>> dateGroup;
			if(queryDTO.getDataType().equals(1)){
				// 日
				dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getPlanDate(),"yyyy/M/d")));
			}else if(queryDTO.getDataType().equals(2)){
				// 周
				dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> String.format("%s~%s",DateUtil.format(DateUtil.beginOfWeek(t.getPlanDate()), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(t.getPlanDate()), "yyyy/M/d"))));
			}else {
				// 月
				dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> String.format("%s月",DateUtil.format(t.getPlanDate(), "yyyy年M"))));
			}
			result.forEach(e -> dateGroup.forEach((k, v) -> {

				// 工单数量
				long planNum = 0L;
				if(e.getType().equals(initTypeArr[0])){
					planNum = v.stream().filter(t -> t.getTimeliness().equals(1)).map(MaintainPlanUserDayCount::getPlanId).distinct().count();
				}else if(e.getType().equals(initTypeArr[1])) {
					planNum = v.stream().filter(t -> t.getTimeliness().equals(2)).map(MaintainPlanUserDayCount::getPlanId).distinct().count();
				}
				e.getTrendData().put(k,BigDecimal.valueOf(planNum));
			}));
		}
		return result;
	}

	@Override
	public List<CheckStatisticsTrendVO> selectCheckTrendEntiretySign(PlanCheckStatisticsQueryDTO queryDTO) {
		String[] initTypeArr = {"正常","系统签退","签到定位异常","签退定位异常"};
		List<CheckStatisticsTrendVO> result = this.initTrendEntirety(queryDTO,initTypeArr);
		List<MaintainPlanUserDayCount> planUserDayCounts = baseMapper.selectByUserDate(queryDTO);
		if(ObjectUtil.isNotEmpty(planUserDayCounts)){
			Map<String,List<MaintainPlanUserDayCount>> dateGroup;
			if(queryDTO.getDataType().equals(1)){
				// 日
				dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getRecordDate(),"yyyy/M/d")));
			}else if(queryDTO.getDataType().equals(2)){
				// 周
				dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> String.format("%s~%s",DateUtil.format(DateUtil.beginOfWeek(t.getRecordDate()), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(t.getRecordDate()), "yyyy/M/d"))));
			}else {
				// 月
				dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> String.format("%s月",DateUtil.format(t.getRecordDate(), "yyyy年M"))));
			}
			result.forEach(e -> dateGroup.forEach((k, v) -> {

				// 统计数量
				long num = 0L;
				if(e.getType().equals(initTypeArr[0])){
					num = v.stream().mapToLong(MaintainPlanUserDayCount::getSignNormal).sum() + v.stream().mapToLong(MaintainPlanUserDayCount::getSignOutNormal).sum();
				}else if(e.getType().equals(initTypeArr[1])) {
					num = v.stream().mapToLong(MaintainPlanUserDayCount::getSignSystem).sum();
				}else if(e.getType().equals(initTypeArr[2])) {
					num = v.stream().mapToLong(MaintainPlanUserDayCount::getSignError).sum();
				}else if(e.getType().equals(initTypeArr[3])) {
					num = v.stream().mapToLong(MaintainPlanUserDayCount::getSignOutError).sum();
				}
				e.getTrendData().put(k,BigDecimal.valueOf(num));
			}));
		}
		return result;
	}

	@Override
	public List<CheckStatisticsTrendVO> selectCheckTrendContrastDeptWorkTime(PlanCheckStatisticsQueryDTO queryDTO) {
		String[] initTypeArr = queryDTO.getDeptGroups().stream().map(DeptGroupDTO::getDeptName).toArray(String[]::new);
		List<CheckStatisticsTrendVO> result = this.initTrendEntirety(queryDTO,initTypeArr);
		queryDTO.getDeptGroups().forEach(g -> {
			queryDTO.setUserIds(g.getUserIds());
			List<MaintainPlanUserDayCount> planUserDayCounts = baseMapper.selectByUserDate(queryDTO);
			if(ObjectUtil.isNotEmpty(planUserDayCounts)){
				Map<String,List<MaintainPlanUserDayCount>> dateGroup;
				if(queryDTO.getDataType().equals(1)){
					// 日
					dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getRecordDate(),"yyyy/M/d")));
				}else if(queryDTO.getDataType().equals(2)){
					// 周
					dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> String.format("%s~%s",DateUtil.format(DateUtil.beginOfWeek(t.getRecordDate()), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(t.getRecordDate()), "yyyy/M/d"))));
				}else {
					// 月
					dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> String.format("%s月",DateUtil.format(t.getRecordDate(), "yyyy年M"))));
				}
				result.forEach(e -> {
					if(e.getType().equals(g.getDeptName())){
						dateGroup.forEach((k, v) -> {
							if(queryDTO.getTemp().equals(1)){
								// 当天总时长
								long workTime = v.stream().mapToLong(MaintainPlanUserDayCount::getWorkTime).sum();
								e.getTrendData().put(k,BigDecimal.valueOf(workTime).divide(BigDecimal.valueOf(60),2,RoundingMode.HALF_UP));
							}else {
								// 当前总工单数
								long planTotal = v.stream().map(MaintainPlanUserDayCount::getPlanId).distinct().count();
								// 当天总时长
								long workTime = v.stream().mapToLong(MaintainPlanUserDayCount::getWorkTime).sum();
								e.getTrendData().put(k,BigDecimal.valueOf(workTime).divide(BigDecimal.valueOf(planTotal),1,RoundingMode.HALF_UP));
							}
						});
					}
				});
			}
		});
		return result;
	}

	@Override
	public List<CheckStatisticsTrendVO> selectCheckTrendContrastUserWorkTime(PlanCheckStatisticsQueryDTO queryDTO) {
		List<User> users = userService.listByIds(queryDTO.getUserIds());
		String[] initTypeArr = users.stream().map(User::getRealName).toArray(String[]::new);
		List<CheckStatisticsTrendVO> result = this.initTrendEntirety(queryDTO,initTypeArr);
		List<MaintainPlanUserDayCount> planUserDayCounts = baseMapper.selectByUserDate(queryDTO);
		if(ObjectUtil.isNotEmpty(planUserDayCounts)){
			Map<String,List<MaintainPlanUserDayCount>> dateGroup;
			if(queryDTO.getDataType().equals(1)){
				// 日
				dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getRecordDate(),"yyyy/M/d")));
			}else if(queryDTO.getDataType().equals(2)){
				// 周
				dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> String.format("%s~%s",DateUtil.format(DateUtil.beginOfWeek(t.getRecordDate()), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(t.getRecordDate()), "yyyy/M/d"))));
			}else {
				// 月
				dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> String.format("%s月",DateUtil.format(t.getRecordDate(), "yyyy年M"))));
			}
			result.forEach(e -> {
				dateGroup.forEach((k, v) -> {
					if(queryDTO.getTemp().equals(1)){
						// 当天总时长
						long workTime = v.stream().filter(g -> g.getUserName().equals(e.getType())).mapToLong(MaintainPlanUserDayCount::getWorkTime).sum();
						e.getTrendData().put(k,BigDecimal.valueOf(workTime).divide(BigDecimal.valueOf(60),2,RoundingMode.HALF_UP));
					}else {
						// 当前总工单数
						long planTotal = v.stream().filter(g -> g.getUserName().equals(e.getType())).map(MaintainPlanUserDayCount::getPlanId).distinct().count();
						// 当天总时长
						long workTime = v.stream().filter(g -> g.getUserName().equals(e.getType())).mapToLong(MaintainPlanUserDayCount::getWorkTime).sum();
						if(planTotal != 0){
							e.getTrendData().put(k,BigDecimal.valueOf(workTime).divide(BigDecimal.valueOf(planTotal),1,RoundingMode.HALF_UP));
						}
					}
				});
			});
		}
		return result;
	}

	@Override
	public List<CheckStatisticsTrendVO> selectCheckTrendContrastDeptStatus(PlanCheckStatisticsQueryDTO queryDTO) {
		String[] initTypeArr = queryDTO.getDeptGroups().stream().map(DeptGroupDTO::getDeptName).toArray(String[]::new);
		List<CheckStatisticsTrendVO> result = this.initTrendEntirety(queryDTO,initTypeArr);
		queryDTO.getDeptGroups().forEach(g -> {
			queryDTO.setUserIds(g.getUserIds());
			List<MaintainPlanUserDayCount> planUserDayCounts = baseMapper.selectPlanStatusByUserDate(queryDTO);
			if(ObjectUtil.isNotEmpty(planUserDayCounts)){
				Map<String,List<MaintainPlanUserDayCount>> dateGroup;
				if(queryDTO.getDataType().equals(1)){
					// 日
					dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getPlanDate(),"yyyy/M/d")));
				}else if(queryDTO.getDataType().equals(2)){
					// 周
					dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> String.format("%s~%s",DateUtil.format(DateUtil.beginOfWeek(t.getPlanDate()), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(t.getPlanDate()), "yyyy/M/d"))));
				}else {
					// 月
					dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> String.format("%s月",DateUtil.format(t.getPlanDate(), "yyyy年M"))));
				}
				result.forEach(e -> {
					if(e.getType().equals(g.getDeptName())){
						dateGroup.forEach((k, v) -> {
							// 工单数量
							long planNum = v.stream().filter(t -> t.getPlanStatus().equals(queryDTO.getTemp())).map(MaintainPlanUserDayCount::getPlanId).distinct().count();
							e.getTrendData().put(k,BigDecimal.valueOf(planNum));
						});
					}
				});
			}
		});
		return result;
	}

	@Override
	public List<CheckStatisticsTrendVO> selectCheckTrendContrastUserStatus(PlanCheckStatisticsQueryDTO queryDTO) {
		List<User> users = userService.listByIds(queryDTO.getUserIds());
		String[] initTypeArr = users.stream().map(User::getRealName).toArray(String[]::new);
		List<CheckStatisticsTrendVO> result = this.initTrendEntirety(queryDTO,initTypeArr);
		List<MaintainPlanUserDayCount> planUserDayCounts = baseMapper.selectPlanStatusByUserDate(queryDTO);
		if(ObjectUtil.isNotEmpty(planUserDayCounts)){
			Map<String,List<MaintainPlanUserDayCount>> dateGroup;
			if(queryDTO.getDataType().equals(1)){
				// 日
				dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getPlanDate(),"yyyy/M/d")));
			}else if(queryDTO.getDataType().equals(2)){
				// 周
				dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> String.format("%s~%s",DateUtil.format(DateUtil.beginOfWeek(t.getPlanDate()), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(t.getPlanDate()), "yyyy/M/d"))));
			}else {
				// 月
				dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> String.format("%s月",DateUtil.format(t.getPlanDate(), "yyyy年M"))));
			}
			result.forEach(e -> {
				dateGroup.forEach((k, v) -> {
					// 工单数量
					long planNum = v.stream().filter(t -> t.getUserName().equals(e.getType()) && t.getPlanStatus().equals(queryDTO.getTemp())).map(MaintainPlanUserDayCount::getPlanId).distinct().count();
					e.getTrendData().put(k,BigDecimal.valueOf(planNum));
				});
			});
		}
		return result;
	}

	@Override
	public List<CheckStatisticsTrendVO> selectCheckTrendContrastDeptTimeliness(PlanCheckStatisticsQueryDTO queryDTO) {
		String[] initTypeArr = queryDTO.getDeptGroups().stream().map(DeptGroupDTO::getDeptName).toArray(String[]::new);
		List<CheckStatisticsTrendVO> result = this.initTrendEntirety(queryDTO,initTypeArr);
		queryDTO.getDeptGroups().forEach(g -> {
			queryDTO.setUserIds(g.getUserIds());
			List<MaintainPlanUserDayCount> planUserDayCounts = baseMapper.selectPlanTimelinessByUserDate(queryDTO);
			if(ObjectUtil.isNotEmpty(planUserDayCounts)){
				Map<String,List<MaintainPlanUserDayCount>> dateGroup;
				if(queryDTO.getDataType().equals(1)){
					// 日
					dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getPlanDate(),"yyyy/M/d")));
				}else if(queryDTO.getDataType().equals(2)){
					// 周
					dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> String.format("%s~%s",DateUtil.format(DateUtil.beginOfWeek(t.getPlanDate()), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(t.getPlanDate()), "yyyy/M/d"))));
				}else {
					// 月
					dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> String.format("%s月",DateUtil.format(t.getPlanDate(), "yyyy年M"))));
				}
				result.forEach(e -> {
					if(e.getType().equals(g.getDeptName())){
						dateGroup.forEach((k, v) -> {
							// 工单数量
							long planNum = v.stream().filter(t -> t.getTimeliness().equals(queryDTO.getTemp())).map(MaintainPlanUserDayCount::getPlanId).distinct().count();
							e.getTrendData().put(k,BigDecimal.valueOf(planNum));
						});
					}
				});
			}
		});
		return result;
	}

	@Override
	public List<CheckStatisticsTrendVO> selectCheckTrendContrastUserTimeliness(PlanCheckStatisticsQueryDTO queryDTO) {
		List<User> users = userService.listByIds(queryDTO.getUserIds());
		String[] initTypeArr = users.stream().map(User::getRealName).toArray(String[]::new);
		List<CheckStatisticsTrendVO> result = this.initTrendEntirety(queryDTO,initTypeArr);
		List<MaintainPlanUserDayCount> planUserDayCounts = baseMapper.selectPlanTimelinessByUserDate(queryDTO);
		if(ObjectUtil.isNotEmpty(planUserDayCounts)){
			Map<String,List<MaintainPlanUserDayCount>> dateGroup;
			if(queryDTO.getDataType().equals(1)){
				// 日
				dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getPlanDate(),"yyyy/M/d")));
			}else if(queryDTO.getDataType().equals(2)){
				// 周
				dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> String.format("%s~%s",DateUtil.format(DateUtil.beginOfWeek(t.getPlanDate()), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(t.getPlanDate()), "yyyy/M/d"))));
			}else {
				// 月
				dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> String.format("%s月",DateUtil.format(t.getPlanDate(), "yyyy年M"))));
			}
			result.forEach(e -> {
				dateGroup.forEach((k, v) -> {
					// 工单数量
					long planNum = v.stream().filter(t -> t.getUserName().equals(e.getType()) && t.getTimeliness().equals(queryDTO.getTemp())).map(MaintainPlanUserDayCount::getPlanId).distinct().count();
					e.getTrendData().put(k,BigDecimal.valueOf(planNum));
				});
			});
		}
		return result;
	}

	@Override
	public List<CheckStatisticsTrendVO> selectCheckTrendContrastDeptSign(PlanCheckStatisticsQueryDTO queryDTO) {
		String[] initTypeArr = queryDTO.getDeptGroups().stream().map(DeptGroupDTO::getDeptName).toArray(String[]::new);
		List<CheckStatisticsTrendVO> result = this.initTrendEntirety(queryDTO,initTypeArr);
		queryDTO.getDeptGroups().forEach(g -> {
			queryDTO.setUserIds(g.getUserIds());
			List<MaintainPlanUserDayCount> planUserDayCounts = baseMapper.selectByUserDate(queryDTO);
			if(ObjectUtil.isNotEmpty(planUserDayCounts)){
				Map<String,List<MaintainPlanUserDayCount>> dateGroup;
				if(queryDTO.getDataType().equals(1)){
					// 日
					dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getRecordDate(),"yyyy/M/d")));
				}else if(queryDTO.getDataType().equals(2)){
					// 周
					dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> String.format("%s~%s",DateUtil.format(DateUtil.beginOfWeek(t.getRecordDate()), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(t.getRecordDate()), "yyyy/M/d"))));
				}else {
					// 月
					dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> String.format("%s月",DateUtil.format(t.getRecordDate(), "yyyy年M"))));
				}
				result.forEach(e -> {
					if(e.getType().equals(g.getDeptName())){
						dateGroup.forEach((k, v) -> {
							// 统计数量
							long num = 0L;
							if(queryDTO.getTemp().equals(1)){
								num = v.stream().mapToLong(MaintainPlanUserDayCount::getSignNormal).sum() + v.stream().mapToLong(MaintainPlanUserDayCount::getSignOutNormal).sum();
							}else if(queryDTO.getTemp().equals(2)) {
								num = v.stream().mapToLong(MaintainPlanUserDayCount::getSignSystem).sum();
							}else if(queryDTO.getTemp().equals(3)) {
								num = v.stream().mapToLong(MaintainPlanUserDayCount::getSignError).sum();
							}else if(queryDTO.getTemp().equals(4)) {
								num = v.stream().mapToLong(MaintainPlanUserDayCount::getSignOutError).sum();
							}
							e.getTrendData().put(k,BigDecimal.valueOf(num));
						});
					}
				});
			}
		});
		return result;
	}

	@Override
	public List<CheckStatisticsTrendVO> selectCheckTrendContrastUserSign(PlanCheckStatisticsQueryDTO queryDTO) {
		List<User> users = userService.listByIds(queryDTO.getUserIds());
		String[] initTypeArr = users.stream().map(User::getRealName).toArray(String[]::new);
		List<CheckStatisticsTrendVO> result = this.initTrendEntirety(queryDTO,initTypeArr);
		List<MaintainPlanUserDayCount> planUserDayCounts = baseMapper.selectByUserDate(queryDTO);
		if(ObjectUtil.isNotEmpty(planUserDayCounts)){
			Map<String,List<MaintainPlanUserDayCount>> dateGroup;
			if(queryDTO.getDataType().equals(1)){
				// 日
				dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getRecordDate(),"yyyy/M/d")));
			}else if(queryDTO.getDataType().equals(2)){
				// 周
				dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> String.format("%s~%s",DateUtil.format(DateUtil.beginOfWeek(t.getRecordDate()), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(t.getRecordDate()), "yyyy/M/d"))));
			}else {
				// 月
				dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> String.format("%s月",DateUtil.format(t.getRecordDate(), "yyyy年M"))));
			}
			result.forEach(e -> {
				dateGroup.forEach((k, v) -> {
					// 统计数量
					long num = 0L;
					if(queryDTO.getTemp().equals(1)){
						num = v.stream().filter(t -> t.getUserName().equals(e.getType())).mapToLong(MaintainPlanUserDayCount::getSignNormal).sum() + v.stream().filter(t -> t.getUserName().equals(e.getType())).mapToLong(MaintainPlanUserDayCount::getSignOutNormal).sum();
					}else if(queryDTO.getTemp().equals(2)) {
						num = v.stream().filter(t -> t.getUserName().equals(e.getType())).mapToLong(MaintainPlanUserDayCount::getSignSystem).sum();
					}else if(queryDTO.getTemp().equals(3)) {
						num = v.stream().filter(t -> t.getUserName().equals(e.getType())).mapToLong(MaintainPlanUserDayCount::getSignError).sum();
					}else if(queryDTO.getTemp().equals(4)) {
						num = v.stream().filter(t -> t.getUserName().equals(e.getType())).mapToLong(MaintainPlanUserDayCount::getSignOutError).sum();
					}
					e.getTrendData().put(k,BigDecimal.valueOf(num));
				});
			});
		}
		return result;
	}

	@Override
	public CheckStatisticsWorkTimeDetailVO selectCheckWorkTimeUserDetail(PlanCheckStatisticsQueryDTO queryDTO) {
		CheckStatisticsWorkTimeDetailVO result = new CheckStatisticsWorkTimeDetailVO();
		List<MaintainSign> signList = signService.listByUserDate(queryDTO,queryDTO.getUserIds());
		if(ObjectUtil.isNotEmpty(signList)){
			// 工单总数
			long planTotal = signList.stream().map(MaintainSign::getPlanId).distinct().count();
			// 总时长
			long workTime = signList.stream().filter(e -> ObjectUtil.isNotEmpty(e.getTimeInterval())).mapToLong(MaintainSign::getTimeInterval).sum();
			if(planTotal != 0){
				result.setWorkTimeHour(BigDecimal.valueOf(workTime).divide(BigDecimal.valueOf(60),2,RoundingMode.HALF_UP));
				result.setWorkTimeMinAve(BigDecimal.valueOf(workTime).divide(BigDecimal.valueOf(planTotal),1,RoundingMode.HALF_UP));
			}
		}
		return result;
	}

	@Override
	public CheckStatisticsStatusDetailVO selectCheckStatusUserDetail(PlanCheckStatisticsQueryDTO queryDTO) {
		List<MaintainPlanContent> planContents = planContentService.listByUserDate(queryDTO,queryDTO.getUserIds());
		CheckStatisticsStatusDetailVO detailVO = new CheckStatisticsStatusDetailVO();

		if(ObjectUtil.isNotEmpty(planContents)){
			// 总工单数
			long planTotal = planContents.stream().map(MaintainPlanContent::getId).distinct().count();
			detailVO.setPlanTotal(planTotal);
			// 未执行
			long toStart = planContents.stream().filter(e -> e.getStatus().equals(TaskStatusEnum.BY_DISABLE.getStatus())).map(MaintainPlanContent::getId).distinct().count();
			// 进行中
			long underway = planContents.stream().filter(e -> e.getStatus().equals(TaskStatusEnum.BY_PROCESSED.getStatus())).map(MaintainPlanContent::getId).distinct().count();
			// 已提交
			long commit = planContents.stream().filter(e -> e.getStatus().equals(TaskStatusEnum.BY_FINISH.getStatus())).map(MaintainPlanContent::getId).distinct().count();
			// 已完成
			long finished = planContents.stream().filter(e -> e.getStatus().equals(TaskStatusEnum.BY_SIGN.getStatus())).map(MaintainPlanContent::getId).distinct().count();
			// 维保签字
			long maintainSignature = planContents.stream().filter(e -> e.getStatus().equals(TaskStatusEnum.BY_MAINTAIN_SIGN.getStatus())).map(MaintainPlanContent::getId).distinct().count();
			if(planTotal != 0){
				detailVO.setToStartPer(BigDecimal.valueOf(toStart).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				detailVO.setUnderwayPer(BigDecimal.valueOf(underway).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				detailVO.setCommitPer(BigDecimal.valueOf(commit).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				detailVO.setFinishedPer(BigDecimal.valueOf(finished).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				detailVO.setMaintainSignaturePer(BigDecimal.valueOf(maintainSignature).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
			}
		}
		return detailVO;
	}

	@Override
	public List<CheckStatisticsUserCountVO> selectCheckStatusUserCount(PlanCheckStatisticsQueryDTO queryDTO) {
//		String[] initType = {"待开始","进行中","提交任务","已完成","维保签字"};
		String[] initType = {"待开始","进行中","提交任务","维保签字","已完成"};
		List<TaskStatusVO> statusList = TaskStatusEnum.getTaskStatusByType(MaintainPlanContentEnum.MAINTAIN_BY.getId());
		List<MaintainPlanContent> planContents = planContentService.listByUserDate(queryDTO,queryDTO.getUserIds());
		List<CheckStatisticsUserCountVO> result = new ArrayList<>();
		for (int i = 0; i < initType.length; i++) {
			// 当前type对应status值
			int status = statusList.get(i).getStatus();
			CheckStatisticsUserCountVO countVO = new CheckStatisticsUserCountVO(initType[i]);
			if(ObjectUtil.isNotEmpty(planContents)){
				// 总工单数
				long planTotal = planContents.stream().mapToLong(MaintainPlanContent::getId).distinct().count();
				// 该类型工单数
				long planTypeTotal = planContents.stream().filter(k -> k.getStatus().equals(status)).mapToLong(MaintainPlanContent::getId).distinct().count();
				countVO.setNum(planTypeTotal);
				countVO.setPer(BigDecimal.valueOf(planTypeTotal).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
			}
			result.add(countVO);
		}
//		if(ObjectUtil.isNotEmpty(planContents)){
//			// 总工单数
//			long planTotal = planContents.stream().mapToLong(MaintainPlanContent::getId).distinct().count();
//			Map<Integer,List<MaintainPlanContent>> statusGroup = planContents.stream().collect(Collectors.groupingBy(MaintainPlanContent::getStatus));
//
//			statusGroup.forEach((k,v) -> {
//				// 该类型工单数
//				long planTypeTotal = v.stream().mapToLong(MaintainPlanContent::getId).distinct().count();
//				CheckStatisticsUserCountVO countVO = new CheckStatisticsUserCountVO();
//				countVO.setNum(planTypeTotal);
//				countVO.setPer(BigDecimal.valueOf(planTypeTotal).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
//				if(k.equals(TaskStatusEnum.BY_DISABLE.getStatus())){
//					countVO.setLabel(initType[0]);
//				}else if(k.equals(TaskStatusEnum.BY_PROCESSED.getStatus())){
//					countVO.setLabel(initType[1]);
//				}else if(k.equals(TaskStatusEnum.BY_FINISH.getStatus())){
//					countVO.setLabel(initType[2]);
//				}else if(k.equals(TaskStatusEnum.BY_SIGN.getStatus())){
//					countVO.setLabel(initType[3]);
//				}
//				result.add(countVO);
//			});
//		}else {
//			for (String type : initType) {
//				CheckStatisticsUserCountVO countVO = new CheckStatisticsUserCountVO(type);
//				result.add(countVO);
//			}
//		}
		return result;
	}

	@Override
	public CheckStatisticsTimelinessDetailVO selectCheckTimelinessUserDetail(PlanCheckStatisticsQueryDTO queryDTO) {
		List<CheckStatisticsPlanSimpleDTO> planContentExts = planContentService.listPlanExtByUserDate(queryDTO,queryDTO.getUserIds());
		CheckStatisticsTimelinessDetailVO result = new CheckStatisticsTimelinessDetailVO();

		if(ObjectUtil.isNotEmpty(planContentExts)){
			// 工单总数
			long planTotal = planContentExts.stream().map(CheckStatisticsPlanSimpleDTO::getPlanId).distinct().count();
			result.setPlanTotal(planTotal);
			if(planTotal != 0){
				// 及时率
				long inTime = planContentExts.stream()
					.filter(k -> (DateUtil.format(k.getPlanDate(),"yyyy-MM-dd").equals(DateUtil.format(DateUtil.date(),"yyyy-MM-dd"))
						&& k.getStatus().equals(TaskStatusEnum.BY_SIGN.getStatus())
						|| (!DateUtil.format(k.getPlanDate(),"yyyy-MM-dd").equals(DateUtil.format(DateUtil.date(),"yyyy-MM-dd"))
						&& ObjectUtil.isEmpty(k.getOverdueDay())))).map(CheckStatisticsPlanSimpleDTO::getPlanId).distinct().count();
				result.setInTimePer(BigDecimal.valueOf(inTime).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				// 逾期率
				long overdue = planContentExts.stream().filter(k ->
						!DateUtil.format(k.getPlanDate(), "yyyy-MM-dd").equals(DateUtil.format(DateUtil.date(), "yyyy-MM-dd")) && ObjectUtil.isNotEmpty(k.getOverdueDay()))
					.map(CheckStatisticsPlanSimpleDTO::getPlanId).distinct().count();
				result.setOverduePer(BigDecimal.valueOf(overdue).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				// 待定
				long undetermined = planContentExts.stream()
					.filter(k -> DateUtil.format(k.getPlanDate(),"yyyy-MM-dd").equals(DateUtil.format(DateUtil.date(),"yyyy-MM-dd"))
						&& !k.getStatus().equals(TaskStatusEnum.BY_SIGN.getStatus())).map(CheckStatisticsPlanSimpleDTO::getPlanId).distinct().count();
				result.setUndeterminedPer(BigDecimal.valueOf(undetermined).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
			}
		}
		return result;
	}

	@Override
	public List<CheckStatisticsUserCountVO> selectCheckTimelinessUserCount(PlanCheckStatisticsQueryDTO queryDTO) {
		String[] initType = {"及时","超时","待定"};
		List<CheckStatisticsPlanSimpleDTO> planContentExts = planContentService.listPlanExtByUserDate(queryDTO,queryDTO.getUserIds());
		List<CheckStatisticsUserCountVO> result = new ArrayList<>();
		if(ObjectUtil.isNotEmpty(planContentExts)){
			// 总工单数
			long planTotal = planContentExts.stream().mapToLong(CheckStatisticsPlanSimpleDTO::getPlanId).distinct().count();
			for (String type : initType) {
				// 该类型工单数
				long planTypeTotal = 0L;
				if(type.equals(initType[0])){
					planTypeTotal = planContentExts.stream().filter(e -> (DateUtil.format(e.getPlanDate(),"yyyy-MM-dd").equals(DateUtil.format(DateUtil.date(),"yyyy-MM-dd"))
						&& e.getStatus().equals(TaskStatusEnum.BY_SIGN.getStatus())
						|| (!DateUtil.format(e.getPlanDate(),"yyyy-MM-dd").equals(DateUtil.format(DateUtil.date(),"yyyy-MM-dd"))
						&& ObjectUtil.isEmpty(e.getOverdueDay())))).mapToLong(CheckStatisticsPlanSimpleDTO::getPlanId).distinct().count();
				}else if(type.equals(initType[1])){
					planTypeTotal = planContentExts.stream().filter(e ->
						!DateUtil.format(e.getPlanDate(), "yyyy-MM-dd").equals(DateUtil.format(DateUtil.date(), "yyyy-MM-dd"))
							&& ObjectUtil.isNotEmpty(e.getOverdueDay())).mapToLong(CheckStatisticsPlanSimpleDTO::getPlanId).distinct().count();
				}else {
					planTypeTotal = planContentExts.stream().filter(e ->
						DateUtil.format(e.getPlanDate(), "yyyy-MM-dd").equals(DateUtil.format(DateUtil.date(), "yyyy-MM-dd"))
							&& e.getStatus() != TaskStatusEnum.BY_SIGN.getStatus()).mapToLong(CheckStatisticsPlanSimpleDTO::getPlanId).distinct().count();
				}
				CheckStatisticsUserCountVO countVO = new CheckStatisticsUserCountVO(type);
				countVO.setNum(planTypeTotal);
				countVO.setPer(BigDecimal.valueOf(planTypeTotal).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				result.add(countVO);
			}
//			Map<String,List<CheckStatisticsPlanSimpleDTO>> timelinessGroup = planContentExts.stream().collect(Collectors.groupingBy(e -> {
//				if((DateUtil.format(e.getPlanDate(),"yyyy-MM-dd").equals(DateUtil.format(DateUtil.date(),"yyyy-MM-dd"))
//					&& e.getStatus().equals(TaskStatusEnum.BY_SIGN.getStatus())
//					|| ObjectUtil.isEmpty(e.getOverdueDay()))){
//					return initType[0];
//				}else if(!DateUtil.format(e.getPlanDate(), "yyyy-MM-dd").equals(DateUtil.format(DateUtil.date(), "yyyy-MM-dd")) && ObjectUtil.isNotEmpty(e.getOverdueDay())){
//					return initType[1];
//				}else {
//					return initType[2];
//				}
//			}));
//			timelinessGroup.forEach((k,v) -> {
//				// 该类型工单数
//				long planTypeTotal = v.stream().mapToLong(CheckStatisticsPlanSimpleDTO::getPlanId).distinct().count();
//				CheckStatisticsUserCountVO countVO = new CheckStatisticsUserCountVO(k);
//				countVO.setNum(planTypeTotal);
//				countVO.setPer(BigDecimal.valueOf(planTypeTotal).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
//				result.add(countVO);
//			});
		}else {
			for (String type : initType) {
				CheckStatisticsUserCountVO countVO = new CheckStatisticsUserCountVO(type);
				result.add(countVO);
			}
		}
		return result;
	}

	@Override
	public CheckStatisticsDurationDetailVO selectCheckDurationUserDetail(PlanCheckStatisticsQueryDTO queryDTO) {
		List<MaintainSign> signList = signService.listCommitByUserDate(queryDTO,queryDTO.getUserIds());
		CheckStatisticsDurationDetailVO result = new CheckStatisticsDurationDetailVO();
		if(ObjectUtil.isNotEmpty(signList)){
			// 总工单数
			long planTotal = signList.stream().map(MaintainSign::getPlanId).distinct().count();
			result.setPlanTotal(planTotal);
			if(planTotal != 0){
				// 工单分组
				Map<Long,List<MaintainSign>> planGroup = signList.stream().collect(Collectors.groupingBy(MaintainSign::getPlanId));
				AtomicLong normal = new AtomicLong(0);
				AtomicLong toLong = new AtomicLong(0);
				AtomicLong toShoot = new AtomicLong(0);
				planGroup.forEach((k,v) -> {
					long timeInterval = v.stream().mapToLong(MaintainSign::getTimeInterval).sum();
					if(timeInterval > 60) {
						toLong.incrementAndGet();
					}else if(timeInterval < 25) {
						toShoot.incrementAndGet();
					}else {
						normal.incrementAndGet();
					}
				});
				result.setNormalPer(BigDecimal.valueOf(normal.get()).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				result.setToLongPer(BigDecimal.valueOf(toLong.get()).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				result.setToShootPer(BigDecimal.valueOf(toShoot.get()).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
			}
		}
		return result;
	}

	@Override
	public List<CheckStatisticsUserCountVO> selectCheckDurationUserCount(PlanCheckStatisticsQueryDTO queryDTO) {
		String[] initType = {"正常(25-60分钟)","时长过长(>60分钟)","时长过短(<25分钟)"};
		List<MaintainSign> signList = signService.listCommitByUserDate(queryDTO,queryDTO.getUserIds());
		List<CheckStatisticsUserCountVO> result = new ArrayList<>();
		if(ObjectUtil.isNotEmpty(signList)){
			// 总工单总数
			long planTotal = signList.stream().map(MaintainSign::getPlanId).distinct().count();
			// 根据工单分组
			Map<Long,BigDecimal> planGroup = signList.stream().collect(Collectors.groupingBy(MaintainSign::getPlanId,Collectors.reducing(BigDecimal.ZERO, t -> BigDecimal.valueOf(t.getTimeInterval()), BigDecimal::add)));
			// 重新转换为集合
			signList = planGroup.entrySet().stream().map(e -> {
				MaintainSign sign = new MaintainSign();
				sign.setPlanId(e.getKey());
				sign.setTimeInterval(e.getValue().longValue());
				return sign;
			}).collect(Collectors.toList());
			for (String type : initType) {
				// 该类型工单数
				long planTypeTotal = 0L;
				if (type.equals(initType[0])){
					planTypeTotal = signList.stream().filter(e -> e.getTimeInterval() >= 25 &&  e.getTimeInterval() <= 60).mapToLong(MaintainSign::getPlanId).distinct().count();
				}else if (type.equals(initType[1])){
					planTypeTotal = signList.stream().filter(e -> e.getTimeInterval() > 60).mapToLong(MaintainSign::getPlanId).distinct().count();
				}else if (type.equals(initType[2])){
					planTypeTotal = signList.stream().filter(e -> e.getTimeInterval() < 25).mapToLong(MaintainSign::getPlanId).distinct().count();
				}
				CheckStatisticsUserCountVO countVO = new CheckStatisticsUserCountVO(type);
				countVO.setNum(planTypeTotal);
				countVO.setPer(BigDecimal.valueOf(planTypeTotal).divide(BigDecimal.valueOf(planTotal), 3, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1, RoundingMode.HALF_UP));
				result.add(countVO);
			}
//			// 根据时长性分组
//			Map<String,List<MaintainSign>> durationGroup = signList.stream().collect(Collectors.groupingBy(e -> {
//				if(e.getTimeInterval() > 60) {
//					return initType[2];
//				}else if(e.getTimeInterval() < 25) {
//					return initType[1];
//				}else {
//					return initType[0];
//				}
//			}));
//			durationGroup.forEach((k,v) -> {
//				// 该类型工单数
//				long planTypeTotal = v.stream().mapToLong(MaintainSign::getPlanId).distinct().count();
//				CheckStatisticsUserCountVO countVO = new CheckStatisticsUserCountVO(k);
//				countVO.setNum(planTypeTotal);
//				countVO.setPer(BigDecimal.valueOf(planTypeTotal).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
//				result.add(countVO);
//			});
		}else {
			for (String type : initType) {
				CheckStatisticsUserCountVO countVO = new CheckStatisticsUserCountVO(type);
				result.add(countVO);
			}
		}
		return result;
	}

	@Override
	public CheckStatisticsSignDetailVO selectCheckSignUserDetail(PlanCheckStatisticsQueryDTO queryDTO) {
		List<MaintainSign> signList = signService.listByUserDate(queryDTO,queryDTO.getUserIds());
		CheckStatisticsSignDetailVO result = new CheckStatisticsSignDetailVO();
		if(ObjectUtil.isNotEmpty(signList)){
			// 总签到次数
			long signCount = signList.stream().filter(k -> ObjectUtil.isNotEmpty(k.getSignTime())).count();
			// 总签退次数
			long signOutCount = signList.stream().filter(k -> ObjectUtil.isNotEmpty(k.getSignOutTime())).count();
			// 总次数
			long signTotal = signCount + signOutCount;
			// 正常次数
			long signNormal = signList.stream().filter(k -> k.getSignStatus() == 1).count();
			long signOutNormal = signList.stream().filter(k -> ObjectUtil.isNotEmpty(k.getSignOutStatus()) && k.getSignOutStatus() == 1).count();
			signNormal = signNormal + signOutNormal;
			// 系统签退次数
			long systemSign = signList.stream().filter(k -> k.getStatus() == 2).count();
			// 签到异常
			long signError = signList.stream().filter(k -> k.getSignStatus() == 2).count();
			// 签退异常
			long signOutError = signList.stream().filter(k -> ObjectUtil.isNotEmpty(k.getSignOutStatus()) && k.getSignOutStatus() == 2).count();
			result.setSignTotal(signTotal);
			result.setSignNormalPer(BigDecimal.valueOf(signNormal).divide(BigDecimal.valueOf(signTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
			result.setSystemSignPer(BigDecimal.valueOf(systemSign).divide(BigDecimal.valueOf(signTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
			result.setSignErrorPer(BigDecimal.valueOf(signError).divide(BigDecimal.valueOf(signTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
			result.setSignOutErrorPer(BigDecimal.valueOf(signOutError).divide(BigDecimal.valueOf(signTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
		}
		return result;
	}

	@Override
	public List<CheckStatisticsUserCountVO> selectCheckSignUserCount(PlanCheckStatisticsQueryDTO queryDTO) {
		String[] initType = {"正常","系统签退","签到定位异常","签退定位异常"};
		List<MaintainSign> signList = signService.listByUserDate(queryDTO,queryDTO.getUserIds());
		List<CheckStatisticsUserCountVO> result = new ArrayList<>();
		if(ObjectUtil.isNotEmpty(signList)){
			// 总签到次数
			long signCount = signList.stream().filter(k -> ObjectUtil.isNotEmpty(k.getSignTime())).count();
			// 总签退次数
			long signOutCount = signList.stream().filter(k -> ObjectUtil.isNotEmpty(k.getSignOutTime())).count();
			// 总次数
			long signTotal = signCount + signOutCount;
			for (String type : initType) {
				CheckStatisticsUserCountVO countVO = new CheckStatisticsUserCountVO(type);
				if(type.equals(initType[0])){
					// 正常次数
					long signNormal = signList.stream().filter(k -> k.getSignStatus() == 1).count();
					long signOutNormal = signList.stream().filter(k -> ObjectUtil.isNotEmpty(k.getSignOutStatus()) && k.getSignOutStatus() == 1).count();
					signNormal = signNormal + signOutNormal;
					countVO.setNum(signNormal);
					countVO.setPer(BigDecimal.valueOf(signNormal).divide(BigDecimal.valueOf(signTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				}else if(type.equals(initType[1])){
					// 系统签退次数
					long systemSign = signList.stream().filter(k -> k.getStatus() == 2).count();
					countVO.setNum(systemSign);
					countVO.setPer(BigDecimal.valueOf(systemSign).divide(BigDecimal.valueOf(signTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				}else if(type.equals(initType[2])){
					// 签到异常
					long signError = signList.stream().filter(k -> k.getSignStatus() == 2).count();
					countVO.setNum(signError);
					countVO.setPer(BigDecimal.valueOf(signError).divide(BigDecimal.valueOf(signTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				}else {
					// 签退异常
					long signOutError = signList.stream().filter(k -> ObjectUtil.isNotEmpty(k.getSignOutStatus()) && k.getSignOutStatus() == 2).count();
					countVO.setNum(signOutError);
					countVO.setPer(BigDecimal.valueOf(signOutError).divide(BigDecimal.valueOf(signTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				}
				result.add(countVO);
			}
		}else {
			for (String type : initType) {
				CheckStatisticsUserCountVO countVO = new CheckStatisticsUserCountVO(type);
				result.add(countVO);
			}
		}
		return result;
	}

	@Override
	public CheckStatisticsOverdueDetailVO selectCheckOverdueDeptDetail(PlanCheckStatisticsQueryDTO queryDTO) {
		List<Long> userIds = queryDTO.getUserIds();
		List<CheckStatisticsPlanSimpleDTO> planContentExts = planContentService.listPlanExtByUserDate(queryDTO,userIds);
		CheckStatisticsOverdueDetailVO result = new CheckStatisticsOverdueDetailVO();
		if(ObjectUtil.isNotEmpty(planContentExts)){
			planContentExts = planContentExts.stream().filter(e -> e.getPlanAuditType().equals(PlanAuditTypeEnum.AUDIT.getStatus())).collect(Collectors.toList());
			// 工单总数
			long planTotal = planContentExts.stream().map(CheckStatisticsPlanSimpleDTO::getPlanId).distinct().count();
			result.setPlanTotal(planTotal);
			List<Long> overduePlan = new ArrayList<>();
			List<Long> normalPlan = new ArrayList<>();
			if(planTotal != 0){
				planContentExts.forEach(e -> {
					if(TaskStatusEnum.BY_SIGN.getStatus() == e.getStatus() || TaskStatusEnum.BY_MAINTAIN_SIGN.getStatus() == e.getStatus()){
						if(ObjectUtil.isNotEmpty(e.getPlanOverdueDate())){
							long maintainSignatureTime = e.getMaintainSignatureTime().getTime();
							long planOverdueDate = e.getPlanOverdueDate().getTime();
							if(maintainSignatureTime > planOverdueDate){
								overduePlan.add(e.getPlanId());
							}else {
								normalPlan.add(e.getPlanId());
							}
						}
					}else {
						if(ObjectUtil.isNotEmpty(e.getElevatorOverdueDate())){
							long planDate = e.getPlanDate().getTime();
							long elevatorOverdueDate = e.getElevatorOverdueDate().getTime();
							long nowDate = DateUtil.parse(DateUtil.today()).getTime();
							if(planDate <= nowDate && planDate > elevatorOverdueDate){
								overduePlan.add(e.getPlanId());
							}else {
								normalPlan.add(e.getPlanId());
							}
						}
					}
				});
				long overdue = overduePlan.stream().distinct().count();
				long normal = normalPlan.stream().distinct().count();
				result.setOverduePer(BigDecimal.valueOf(overdue).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				result.setNormalPer(BigDecimal.valueOf(normal).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
			}
		}
		return result;
	}

	@Override
	public List<CheckStatisticsOverdueCountVO> selectCheckOverdueDeptCount(PlanCheckStatisticsQueryDTO queryDTO) {
		List<Long> userIds = this.initDeptUserIds(queryDTO);
		List<CheckStatisticsPlanSimpleDTO> planContentExts = planContentService.listPlanExtByUserDate(queryDTO,userIds);
		List<CheckStatisticsOverdueCountVO> result = new ArrayList<>();
		if(ObjectUtil.isNotEmpty(planContentExts)){
			List<CheckStatisticsPlanSimpleDTO> finalPlanContentExts = planContentExts.stream().filter(e -> e.getPlanAuditType().equals(PlanAuditTypeEnum.AUDIT.getStatus())).collect(Collectors.toList());
			queryDTO.getDeptGroups().forEach(e -> {

				CheckStatisticsOverdueCountVO countVO = new CheckStatisticsOverdueCountVO(e.getDeptName());
				// 工单总数
				long planTotal = finalPlanContentExts.stream().filter(k -> e.getUserIds().contains(k.getUserId())).map(CheckStatisticsPlanSimpleDTO::getPlanId).distinct().count();
				if(planTotal != 0){

					// 逾期
					List<Long> overduePlan = new ArrayList<>();
					// 正常
					List<Long> normalPlan = new ArrayList<>();
					finalPlanContentExts.forEach(k -> {
						if(e.getUserIds().contains(k.getUserId())){
							if(TaskStatusEnum.BY_SIGN.getStatus() == k.getStatus() || TaskStatusEnum.BY_MAINTAIN_SIGN.getStatus() == k.getStatus()){
								if(ObjectUtil.isNotEmpty(k.getPlanOverdueDate())){
									long maintainSignatureTime = k.getMaintainSignatureTime().getTime();
									long planOverdueDate = k.getPlanOverdueDate().getTime();
									if(maintainSignatureTime > planOverdueDate){
										overduePlan.add(k.getPlanId());
									}else {
										normalPlan.add(k.getPlanId());
									}
								}
							}else {
								if(ObjectUtil.isNotEmpty(k.getElevatorOverdueDate())){
									long planDate = k.getPlanDate().getTime();
									long elevatorOverdueDate = k.getElevatorOverdueDate().getTime();
									long nowDate = DateUtil.parse(DateUtil.today()).getTime();
									if(planDate <= nowDate && planDate > elevatorOverdueDate){
										overduePlan.add(k.getPlanId());
									}else {
										normalPlan.add(k.getPlanId());
									}
								}
							}
						}
					});
					long overdue = overduePlan.stream().distinct().count();
					long normal = normalPlan.stream().distinct().count();
					countVO.setOverdue(overdue);
					countVO.setOverduePer(BigDecimal.valueOf(overdue).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
					countVO.setNormal(normal);
					countVO.setNormalPer(BigDecimal.valueOf(normal).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				}
				result.add(countVO);

			});
		}else {
			queryDTO.getDeptGroups().forEach(e -> {
				CheckStatisticsOverdueCountVO countVO = new CheckStatisticsOverdueCountVO(e.getDeptName());
				result.add(countVO);
			});
		}
		return result;
	}

	@Override
	public List<CheckStatisticsOverdueCountVO> selectCheckOverdueDeptUserCount(PlanCheckStatisticsQueryDTO queryDTO) {
		List<User> users = userService.listByIds(queryDTO.getUserIds());
		List<CheckStatisticsPlanSimpleDTO> planContentExts = planContentService.listPlanExtByUserDate(queryDTO,queryDTO.getUserIds());
		List<CheckStatisticsOverdueCountVO> result = new ArrayList<>();
		if(ObjectUtil.isNotEmpty(planContentExts)){

			List<CheckStatisticsPlanSimpleDTO> finalPlanContentExts = planContentExts.stream().filter(e -> e.getPlanAuditType().equals(PlanAuditTypeEnum.AUDIT.getStatus())).collect(Collectors.toList());

			CheckStatisticsOverdueCountVO totalVO = new CheckStatisticsOverdueCountVO("全部");
			// 工单总数
			long totalPlanTotal = planContentExts.stream().map(CheckStatisticsPlanSimpleDTO::getPlanId).distinct().count();
			// 逾期总数
			List<Long> totalOverduePlan = new ArrayList<>();
			// 正常总数
			List<Long> totalNormalPlan = new ArrayList<>();
			users.forEach(e -> {
				CheckStatisticsOverdueCountVO countVO = new CheckStatisticsOverdueCountVO(e.getRealName());
				// 工单总数
				long planTotal = finalPlanContentExts.stream().filter(k -> e.getId().equals(k.getUserId())).map(CheckStatisticsPlanSimpleDTO::getPlanId).distinct().count();
				countVO.setPlanTotal(planTotal);
				// 逾期总数
				List<Long> overduePlan = new ArrayList<>();
				// 正常总数
				List<Long> normalPlan = new ArrayList<>();
				if(planTotal != 0){
					finalPlanContentExts.forEach(k -> {
						if(k.getUserId().equals(e.getId())){
							if(TaskStatusEnum.BY_SIGN.getStatus() == k.getStatus() || TaskStatusEnum.BY_MAINTAIN_SIGN.getStatus() == k.getStatus()){
								if(ObjectUtil.isNotEmpty(k.getPlanOverdueDate())){
									long maintainSignatureTime = k.getMaintainSignatureTime().getTime();
									long planOverdueDate = k.getPlanOverdueDate().getTime();
									if(maintainSignatureTime > planOverdueDate){
										overduePlan.add(k.getPlanId());
										totalOverduePlan.add(k.getPlanId());
									}else {
										normalPlan.add(k.getPlanId());
										totalNormalPlan.add(k.getPlanId());
									}
								}
							}else {
								if(ObjectUtil.isNotEmpty(k.getElevatorOverdueDate())){
									long planDate = k.getPlanDate().getTime();
									long elevatorOverdueDate = k.getElevatorOverdueDate().getTime();
									long nowDate = DateUtil.parse(DateUtil.today()).getTime();
									if(planDate <= nowDate && planDate > elevatorOverdueDate){
										overduePlan.add(k.getPlanId());
										totalOverduePlan.add(k.getPlanId());
									}else {
										normalPlan.add(k.getPlanId());
										totalNormalPlan.add(k.getPlanId());
									}
								}
							}
						}
					});
					long overdue = overduePlan.stream().distinct().count();
					long normal = normalPlan.stream().distinct().count();
					countVO.setOverdue(overdue);
					countVO.setNormal(normal);
					countVO.setOverduePer(BigDecimal.valueOf(overdue).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
					countVO.setNormalPer(BigDecimal.valueOf(normal).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				}
				result.add(countVO);
			});

			if(ObjectUtil.isNotEmpty(totalPlanTotal)){
				totalVO.setPlanTotal(totalPlanTotal);
				totalVO.setNormal(totalNormalPlan.stream().distinct().count());
				totalVO.setOverdue(totalOverduePlan.stream().distinct().count());
				totalVO.setNormalPer(BigDecimal.valueOf(totalVO.getNormal()).divide(BigDecimal.valueOf(totalPlanTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				totalVO.setOverduePer(BigDecimal.valueOf(totalVO.getOverdue()).divide(BigDecimal.valueOf(totalPlanTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
			}
			result.add(0,totalVO);
		}else {
			CheckStatisticsOverdueCountVO totalVO = new CheckStatisticsOverdueCountVO("全部");
			result.add(totalVO);
			users.forEach(e -> {
				CheckStatisticsOverdueCountVO countVO = new CheckStatisticsOverdueCountVO(e.getRealName());
				result.add(countVO);
			});
		}
		return result;
	}

	@Override
	public List<CheckStatisticsTrendVO> selectCheckTrendEntiretyOverdue(PlanCheckStatisticsQueryDTO queryDTO) {
		String[] initTypeArr = {"未逾期","已逾期"};
		List<CheckStatisticsTrendVO> result = this.initTrendEntirety(queryDTO,initTypeArr);
		List<MaintainPlanUserDayCount> planUserDayCounts = baseMapper.selectPlanOverdueByUserDate(queryDTO);
		if(ObjectUtil.isNotEmpty(planUserDayCounts)){
			planUserDayCounts = planUserDayCounts.stream().filter(e -> e.getPlanAuditType().equals(PlanAuditTypeEnum.AUDIT.getStatus())).collect(Collectors.toList());
			Map<String,List<MaintainPlanUserDayCount>> dateGroup;
			if(queryDTO.getDataType().equals(1)){
				// 日
				dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getPlanDate(),"yyyy/M/d")));
			}else if(queryDTO.getDataType().equals(2)){
				// 周
				dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> String.format("%s~%s",DateUtil.format(DateUtil.beginOfWeek(t.getPlanDate()), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(t.getPlanDate()), "yyyy/M/d"))));
			}else {
				// 月
				dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> String.format("%s月",DateUtil.format(t.getPlanDate(), "yyyy年M"))));
			}
			result.forEach(e -> dateGroup.forEach((k, v) -> {

				// 工单数量
				long planNum = 0L;
				if(e.getType().equals(initTypeArr[0])){
					planNum = v.stream().filter(t -> ObjectUtil.isNotEmpty(t.getOverdue()) && t.getOverdue().equals(PlanOverdueEnum.NORMAL.getStatus())).map(MaintainPlanUserDayCount::getPlanId).distinct().count();
				}else if(e.getType().equals(initTypeArr[1])) {
					planNum = v.stream().filter(t -> ObjectUtil.isNotEmpty(t.getOverdue()) && t.getOverdue().equals(PlanOverdueEnum.OVERDUE.getStatus())).map(MaintainPlanUserDayCount::getPlanId).distinct().count();
				}
				e.getTrendData().put(k,BigDecimal.valueOf(planNum));
			}));
		}
		return result;
	}

	@Override
	public List<CheckStatisticsTrendVO> selectCheckTrendContrastDeptOverdue(PlanCheckStatisticsQueryDTO queryDTO) {
		String[] initTypeArr = queryDTO.getDeptGroups().stream().map(DeptGroupDTO::getDeptName).toArray(String[]::new);
		List<CheckStatisticsTrendVO> result = this.initTrendEntirety(queryDTO,initTypeArr);
		queryDTO.getDeptGroups().forEach(g -> {
			queryDTO.setUserIds(g.getUserIds());
			List<MaintainPlanUserDayCount> planUserDayCounts = baseMapper.selectPlanOverdueByUserDate(queryDTO);
			planUserDayCounts = planUserDayCounts.stream().filter(e -> e.getPlanAuditType().equals(PlanAuditTypeEnum.AUDIT.getStatus())).collect(Collectors.toList());
			if(ObjectUtil.isNotEmpty(planUserDayCounts)){
				Map<String,List<MaintainPlanUserDayCount>> dateGroup;
				if(queryDTO.getDataType().equals(1)){
					// 日
					dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getPlanDate(),"yyyy/M/d")));
				}else if(queryDTO.getDataType().equals(2)){
					// 周
					dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> String.format("%s~%s",DateUtil.format(DateUtil.beginOfWeek(t.getPlanDate()), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(t.getPlanDate()), "yyyy/M/d"))));
				}else {
					// 月
					dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> String.format("%s月",DateUtil.format(t.getPlanDate(), "yyyy年M"))));
				}
				result.forEach(e -> {
					if(e.getType().equals(g.getDeptName())){
						dateGroup.forEach((k, v) -> {
							// 工单数量
							long planNum = v.stream().filter(t -> ObjectUtil.isNotEmpty(t.getOverdue()) && t.getOverdue().equals(queryDTO.getTemp())).map(MaintainPlanUserDayCount::getPlanId).distinct().count();
							e.getTrendData().put(k,BigDecimal.valueOf(planNum));
						});
					}
				});
			}
		});
		return result;
	}

	@Override
	public List<CheckStatisticsTrendVO> selectCheckTrendContrastUserOverdue(PlanCheckStatisticsQueryDTO queryDTO) {
		List<User> users = userService.listByIds(queryDTO.getUserIds());
		String[] initTypeArr = users.stream().map(User::getRealName).toArray(String[]::new);
		List<CheckStatisticsTrendVO> result = this.initTrendEntirety(queryDTO,initTypeArr);
		List<MaintainPlanUserDayCount> planUserDayCounts = baseMapper.selectPlanOverdueByUserDate(queryDTO);
		if(ObjectUtil.isNotEmpty(planUserDayCounts)){
			planUserDayCounts = planUserDayCounts.stream().filter(e -> e.getPlanAuditType().equals(PlanAuditTypeEnum.AUDIT.getStatus())).collect(Collectors.toList());
			Map<String,List<MaintainPlanUserDayCount>> dateGroup;
			if(queryDTO.getDataType().equals(1)){
				// 日
				dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getPlanDate(),"yyyy/M/d")));
			}else if(queryDTO.getDataType().equals(2)){
				// 周
				dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> String.format("%s~%s",DateUtil.format(DateUtil.beginOfWeek(t.getPlanDate()), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(t.getPlanDate()), "yyyy/M/d"))));
			}else {
				// 月
				dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> String.format("%s月",DateUtil.format(t.getPlanDate(), "yyyy年M"))));
			}
			result.forEach(e -> {
				dateGroup.forEach((k, v) -> {
					// 工单数量
					long planNum = v.stream().filter(t -> t.getUserName().equals(e.getType()) && ObjectUtil.isNotEmpty(t.getOverdue()) && t.getOverdue().equals(queryDTO.getTemp())).map(MaintainPlanUserDayCount::getPlanId).distinct().count();
					e.getTrendData().put(k,BigDecimal.valueOf(planNum));
				});
			});
		}
		return result;
	}

	@Override
	public CheckStatisticsOverdueDetailVO selectCheckOverdueUserDetail(PlanCheckStatisticsQueryDTO queryDTO) {
		List<Long> userIds = queryDTO.getUserIds();
		List<CheckStatisticsPlanSimpleDTO> planContentExts = planContentService.listPlanExtByUserDate(queryDTO,userIds);
		CheckStatisticsOverdueDetailVO result = new CheckStatisticsOverdueDetailVO();
		if(ObjectUtil.isNotEmpty(planContentExts)){
			planContentExts = planContentExts.stream().filter(e -> e.getPlanAuditType().equals(PlanAuditTypeEnum.AUDIT.getStatus())).collect(Collectors.toList());
			// 工单总数
			long planTotal = planContentExts.stream().map(CheckStatisticsPlanSimpleDTO::getPlanId).distinct().count();
			result.setPlanTotal(planTotal);
			List<Long> overduePlan = new ArrayList<>();
			List<Long> normalPlan = new ArrayList<>();
			if(planTotal != 0){
				planContentExts.forEach(e -> {
					if(TaskStatusEnum.BY_SIGN.getStatus() == e.getStatus() || TaskStatusEnum.BY_MAINTAIN_SIGN.getStatus() == e.getStatus()){
						if(ObjectUtil.isNotEmpty(e.getPlanOverdueDate())){
							long maintainSignatureTime = e.getMaintainSignatureTime().getTime();
							long planOverdueDate = e.getPlanOverdueDate().getTime();
							if(maintainSignatureTime > planOverdueDate){
								overduePlan.add(e.getPlanId());
							}else {
								normalPlan.add(e.getPlanId());
							}
						}
					}else {
						if(ObjectUtil.isNotEmpty(e.getElevatorOverdueDate())){
							long planDate = e.getPlanDate().getTime();
							long elevatorOverdueDate = e.getElevatorOverdueDate().getTime();
							long nowDate = DateUtil.parse(DateUtil.today()).getTime();
							if(planDate <= nowDate && planDate > elevatorOverdueDate){
								overduePlan.add(e.getPlanId());
							}else {
								normalPlan.add(e.getPlanId());
							}
						}
					}
				});
				long overdue = overduePlan.stream().distinct().count();
				long normal = normalPlan.stream().distinct().count();
				result.setOverduePer(BigDecimal.valueOf(overdue).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				result.setNormalPer(BigDecimal.valueOf(normal).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
			}
		}
		return result;
	}

	@Override
	public List<CheckStatisticsUserCountVO> selectCheckOverdueUserCount(PlanCheckStatisticsQueryDTO queryDTO) {
		String[] initType = {"未逾期","已逾期"};
		List<CheckStatisticsPlanSimpleDTO> planContentExts = planContentService.listPlanExtByUserDate(queryDTO,queryDTO.getUserIds());
		List<CheckStatisticsUserCountVO> result = new ArrayList<>();
		if(ObjectUtil.isNotEmpty(planContentExts)){
			planContentExts = planContentExts.stream().filter(e -> e.getPlanAuditType().equals(PlanAuditTypeEnum.AUDIT.getStatus())).collect(Collectors.toList());
			// 总工单数
			long planTotal = planContentExts.stream().mapToLong(CheckStatisticsPlanSimpleDTO::getPlanId).distinct().count();
			for (String type : initType) {
				// 该类型工单数
				long planTypeTotal = 0L;
				if(type.equals(initType[0])){
					planTypeTotal = planContentExts.stream().filter(e -> {
						if(e.getStatus().equals(TaskStatusEnum.BY_MAINTAIN_SIGN.getStatus()) || e.getStatus().equals(TaskStatusEnum.BY_SIGN.getStatus())){
							if(ObjectUtil.isNotEmpty(e.getPlanOverdueDate())){
								long maintainSignatureTime = e.getMaintainSignatureTime().getTime();
								long planOverdueDate = e.getPlanOverdueDate().getTime();
								if(maintainSignatureTime <= planOverdueDate){
									return Boolean.TRUE;
								}
							}
						}else {
							if(ObjectUtil.isNotEmpty(e.getElevatorOverdueDate())){
								long nowDate = DateUtil.parse(DateUtil.today()).getTime();
								long elevatorOverdueDate = e.getElevatorOverdueDate().getTime();
								long planDate = e.getPlanDate().getTime();
								if(planDate <= nowDate && nowDate <= elevatorOverdueDate){
									return Boolean.TRUE;
								}
							}
						}
						return Boolean.FALSE;
					}).mapToLong(CheckStatisticsPlanSimpleDTO::getPlanId).distinct().count();
				}else if(type.equals(initType[1])){
					planTypeTotal = planContentExts.stream().filter(e -> {
						if(e.getStatus().equals(TaskStatusEnum.BY_MAINTAIN_SIGN.getStatus()) || e.getStatus().equals(TaskStatusEnum.BY_SIGN.getStatus())){
							if(ObjectUtil.isNotEmpty(e.getPlanOverdueDate())){
								long maintainSignatureTime = e.getMaintainSignatureTime().getTime();
								long planOverdueDate = e.getPlanOverdueDate().getTime();
								if(maintainSignatureTime > planOverdueDate){
									return Boolean.TRUE;
								}
							}
						}else {
							if(ObjectUtil.isNotEmpty(e.getElevatorOverdueDate())){
								long nowDate = DateUtil.parse(DateUtil.today()).getTime();
								long elevatorOverdueDate = e.getElevatorOverdueDate().getTime();
								long planDate = e.getPlanDate().getTime();
								if(planDate <= nowDate && nowDate > elevatorOverdueDate){
									return Boolean.TRUE;
								}
							}
						}
						return Boolean.FALSE;
					}).mapToLong(CheckStatisticsPlanSimpleDTO::getPlanId).distinct().count();
				}
				CheckStatisticsUserCountVO countVO = new CheckStatisticsUserCountVO(type);
				if(planTypeTotal != 0){
					countVO.setNum(planTypeTotal);
					countVO.setPer(BigDecimal.valueOf(planTypeTotal).divide(BigDecimal.valueOf(planTotal),3,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(1,RoundingMode.HALF_UP));
				}
				result.add(countVO);
			}
		}

		return result;
	}

	@Override
	public List<CheckStatisticsTrendVO> selectCheckTrendEntiretyWorkDuration(PlanCheckStatisticsQueryDTO queryDTO) {
		String[] initTypeArr = {"已保养作业工单数","工单平均作业时长"};
		List<CheckStatisticsTrendVO> result = this.initTrendEntirety(queryDTO,initTypeArr);
		List<Long> planIds = baseMapper.selectCheckPlanIds(queryDTO,queryDTO.getUserIds());
		if(ObjectUtil.isNotEmpty(planIds)){
			List<MaintainPlanUserDayCount> planUserDayCounts = baseMapper.selectByUserDateV2(planIds);
			Map<String,List<MaintainPlanUserDayCount>> dateGroup;
			if(queryDTO.getDataType().equals(1)){
				// 日
				dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getPlanDate(),"yyyy/M/d")));
			}else if(queryDTO.getDataType().equals(2)){
				// 周
				dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> String.format("%s~%s",DateUtil.format(DateUtil.beginOfWeek(t.getPlanDate()), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(t.getPlanDate()), "yyyy/M/d"))));
			}else {
				// 月
				dateGroup = planUserDayCounts.stream().collect(Collectors.groupingBy(t -> String.format("%s月",DateUtil.format(t.getPlanDate(), "yyyy年M"))));
			}
			// 已保养作业工单数
			result.forEach(e -> dateGroup.forEach((k, v) -> {
				if(e.getType().equals(initTypeArr[0])){
					long planTotal = v.stream().map(MaintainPlanUserDayCount::getPlanId).distinct().count();
					e.getTrendData().put(k,planTotal);
				}else {
					// 当前已完成总工单数
					long planTotal = v.stream().map(MaintainPlanUserDayCount::getPlanId).distinct().count();
					// 当天总时长
					long workTime = v.stream().mapToLong(MaintainPlanUserDayCount::getWorkDuration).sum();
					if(planTotal > 0){
						e.getTrendData().put(k,BigDecimal.valueOf(workTime).divide(BigDecimal.valueOf(planTotal),1,RoundingMode.HALF_UP));
					}else {
						e.getTrendData().put(k,BigDecimal.valueOf(0));
					}
				}
			}));
		}
		return result;
	}

	@Override
	public CheckStatisticsWorkTimeDetailVO selectCheckWorkDurationDeptDetail(PlanCheckStatisticsQueryDTO queryDTO) {
		List<Long> planIds = baseMapper.selectCheckPlanIds(queryDTO,queryDTO.getUserIds());
		CheckStatisticsWorkTimeDetailVO statisticsDetailVO = new CheckStatisticsWorkTimeDetailVO();
		if(Func.isNotEmpty(planIds)){
			statisticsDetailVO = baseMapper.selectCheckWorkDurationDeptDetail(planIds);
			statisticsDetailVO.setWorkTimeMinAve(statisticsDetailVO.getWorkTimeHour().divide(BigDecimal.valueOf(statisticsDetailVO.getPlanTotal()),1,RoundingMode.HALF_UP));
			statisticsDetailVO.setWorkTimeHour(statisticsDetailVO.getWorkTimeHour().divide(BigDecimal.valueOf(60),2,RoundingMode.HALF_UP));
		}
		return statisticsDetailVO;
	}

	@Override
	public CheckStatisticsWorkTimeDetailVO selectCheckWorkDurationUserDetail(PlanCheckStatisticsQueryDTO queryDTO) {
		List<Long> planIds = baseMapper.selectCheckPlanIds(queryDTO,queryDTO.getUserIds());
		CheckStatisticsWorkTimeDetailVO statisticsDetailVO = new CheckStatisticsWorkTimeDetailVO();
		if(Func.isNotEmpty(planIds)){
			statisticsDetailVO = baseMapper.selectCheckWorkDurationDeptDetail(planIds);
			statisticsDetailVO.setWorkTimeMinAve(statisticsDetailVO.getWorkTimeHour().divide(BigDecimal.valueOf(statisticsDetailVO.getPlanTotal()),1,RoundingMode.HALF_UP));
			statisticsDetailVO.setWorkTimeHour(statisticsDetailVO.getWorkTimeHour().divide(BigDecimal.valueOf(60),2,RoundingMode.HALF_UP));
		}
		return statisticsDetailVO;
	}

	@Override
	public List<CheckStatisticsWorkTimeCountVO> selectCheckWorkDurationDeptCount(PlanCheckStatisticsQueryDTO queryDTO) {
		List<Long> userIds = this.initDeptUserIds(queryDTO);
		List<CheckStatisticsWorkTimeCountVO> result = new ArrayList<>();
		List<Long> planIds = baseMapper.selectCheckPlanIds(queryDTO,userIds);
		if(ObjectUtil.isNotEmpty(planIds)){
			List<MaintainPlanUserDayCount> planUserDayCounts = baseMapper.selectByUserDateV2(planIds);
			queryDTO.getDeptGroups().forEach(e -> {
				CheckStatisticsWorkTimeCountVO countVO = new CheckStatisticsWorkTimeCountVO(e.getDeptName());
				if(e.getDeptId() == -1){
					// 组总工单数
					long planTotal = planUserDayCounts.stream().map(MaintainPlanUserDayCount::getPlanId).distinct().count();
					countVO.setPlanTotal(planTotal);
					// 组总时长
					long timeInterval = planUserDayCounts.stream().mapToLong(MaintainPlanUserDayCount::getWorkDuration).sum();
					countVO.setWorkTimeHour(BigDecimal.valueOf(timeInterval).divide(BigDecimal.valueOf(60),2,RoundingMode.HALF_UP));

					if(planTotal != 0){
						// 组工单平均时长
						countVO.setWorkTimeMinAve(BigDecimal.valueOf(timeInterval).divide(BigDecimal.valueOf(planTotal),1,RoundingMode.HALF_UP));
					}
				}else {
					// 组总工单数
					long planTotal = planUserDayCounts.stream().filter(k -> k.getUserDeptIds().contains(String.valueOf(e.getDeptId()))).map(MaintainPlanUserDayCount::getPlanId).distinct().count();
					countVO.setPlanTotal(planTotal);
					// 组总时长
					long timeInterval = planUserDayCounts.stream().filter(k -> k.getUserDeptIds().contains(String.valueOf(e.getDeptId()))).mapToLong(MaintainPlanUserDayCount::getWorkDuration).sum();
					countVO.setWorkTimeHour(BigDecimal.valueOf(timeInterval).divide(BigDecimal.valueOf(60),2,RoundingMode.HALF_UP));

					if(planTotal != 0){
						// 组工单平均时长
						countVO.setWorkTimeMinAve(BigDecimal.valueOf(timeInterval).divide(BigDecimal.valueOf(planTotal),1,RoundingMode.HALF_UP));
					}
				}
				result.add(countVO);
			});
		}else {
			queryDTO.getDeptGroups().forEach(e -> {
				CheckStatisticsWorkTimeCountVO countVO = new CheckStatisticsWorkTimeCountVO(e.getDeptName());
				result.add(countVO);
			});
		}
		return result;
	}

	@Override
	public List<CheckStatisticsWorkTimeCountVO> selectCheckWorkDurationDeptUserCount(PlanCheckStatisticsQueryDTO queryDTO) {
		List<User> users = userService.listByIds(queryDTO.getUserIds());
		List<CheckStatisticsWorkTimeCountVO> result = new ArrayList<>();
		List<Long> planIds = baseMapper.selectCheckPlanIds(queryDTO,queryDTO.getUserIds());
		if(ObjectUtil.isNotEmpty(planIds)){
			List<MaintainPlanUserDayCount> planUserDayCounts = baseMapper.selectByUserDateV2(planIds);

			// 总工单数
			long totalPlanTotal = planUserDayCounts.stream().map(MaintainPlanUserDayCount::getPlanId).distinct().count();
			// 总作业天数
			long totalDayTotal = planUserDayCounts.stream().map(j -> DateUtil.format(j.getPlanDate(),"yyyy-MM-dd")).distinct().count();
			// 总时长
			long totalTimeInterval = planUserDayCounts.stream().mapToLong(MaintainPlanUserDayCount::getWorkDuration).sum();

			users.forEach(e -> {
				CheckStatisticsWorkTimeCountVO countVO = new CheckStatisticsWorkTimeCountVO(e.getRealName());

				List<MaintainPlanUserDayCount> userPlanList = planUserDayCounts.stream().filter(t -> t.getPlanUserIds().contains(String.valueOf(e.getId()))).collect(Collectors.toList());
				if(ObjectUtil.isNotEmpty(userPlanList)){

					// 每人总工单数
					long planTotal = userPlanList.stream().map(MaintainPlanUserDayCount::getPlanId).distinct().count();
					countVO.setPlanTotal(planTotal);
					// 每人总作业天数
					long dayTotal = userPlanList.stream().map(j -> DateUtil.format(j.getPlanDate(),"yyyy-MM-dd")).distinct().count();
					countVO.setDayWork(dayTotal);

					// 每人总时长
					long timeInterval = userPlanList.stream().mapToLong(MaintainPlanUserDayCount::getWorkDuration).sum();
					countVO.setWorkTimeHour(BigDecimal.valueOf(timeInterval).divide(BigDecimal.valueOf(60),2,RoundingMode.HALF_UP));

					if(planTotal != 0){
						// 每人工单平均时长
						countVO.setWorkTimeMinAve(BigDecimal.valueOf(timeInterval).divide(BigDecimal.valueOf(planTotal),1,RoundingMode.HALF_UP));
					}
				}
				result.add(countVO);
			});

			CheckStatisticsWorkTimeCountVO totalVO = new CheckStatisticsWorkTimeCountVO("全部");
			if(totalPlanTotal != 0){
				totalVO.setPlanTotal(totalPlanTotal);
				// 总时长
				totalVO.setWorkTimeHour(BigDecimal.valueOf(totalTimeInterval).divide(BigDecimal.valueOf(60),2,RoundingMode.HALF_UP));
				// 人工单平均时长
				totalVO.setWorkTimeMinAve(BigDecimal.valueOf(totalTimeInterval).divide(BigDecimal.valueOf(totalPlanTotal),1,RoundingMode.HALF_UP));
				// 总天数
				totalVO.setDayWork(totalDayTotal);
			}
			result.add(0,totalVO);
		}else {
			CheckStatisticsWorkTimeCountVO totalVO = new CheckStatisticsWorkTimeCountVO("全部");
			result.add(totalVO);
			users.forEach(e -> {
				CheckStatisticsWorkTimeCountVO countVO = new CheckStatisticsWorkTimeCountVO(e.getRealName());
				result.add(countVO);
			});
		}
		return result;
	}

	@Override
	public List<CheckStatisticsTrendVO> selectCheckTrendContrastDeptWorkDuration(PlanCheckStatisticsQueryDTO queryDTO) {
		String[] initTypeArr = queryDTO.getDeptGroups().stream().map(DeptGroupDTO::getDeptName).toArray(String[]::new);
		List<CheckStatisticsTrendVO> result = this.initTrendEntirety(queryDTO,initTypeArr);
		List<Long> userIds = this.initDeptUserIds(queryDTO);
		List<Long> planIds = baseMapper.selectCheckPlanIds(queryDTO,userIds);
		if(Func.isNotEmpty(planIds)){
			List<MaintainPlanUserDayCount> planUserDayCounts = baseMapper.selectByUserDateV2(planIds);
			queryDTO.getDeptGroups().forEach(g -> {
				List<MaintainPlanUserDayCount> groupPlanList = planUserDayCounts.stream().filter(t -> t.getUserDeptIds().contains(String.valueOf(g.getDeptId()))).collect(Collectors.toList());
				if(ObjectUtil.isNotEmpty(groupPlanList)){
					Map<String,List<MaintainPlanUserDayCount>> dateGroup;
					if(queryDTO.getDataType().equals(1)){
						// 日
						dateGroup = groupPlanList.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getPlanDate(),"yyyy/M/d")));
					}else if(queryDTO.getDataType().equals(2)){
						// 周
						dateGroup = groupPlanList.stream().collect(Collectors.groupingBy(t -> String.format("%s~%s",DateUtil.format(DateUtil.beginOfWeek(t.getPlanDate()), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(t.getPlanDate()), "yyyy/M/d"))));
					}else {
						// 月
						dateGroup = groupPlanList.stream().collect(Collectors.groupingBy(t -> String.format("%s月",DateUtil.format(t.getPlanDate(), "yyyy年M"))));
					}
					result.forEach(e -> {
						if(e.getType().equals(g.getDeptName())){
							dateGroup.forEach((k, v) -> {
								if(queryDTO.getTemp().equals(1)){
									// 当前总工单数
									long planTotal = v.stream().map(MaintainPlanUserDayCount::getPlanId).distinct().count();
									e.getTrendData().put(k,planTotal);
								}else {
									// 当前总工单数
									long planTotal = v.stream().map(MaintainPlanUserDayCount::getPlanId).distinct().count();
									// 当天总时长
									long workTime = v.stream().mapToLong(MaintainPlanUserDayCount::getWorkDuration).sum();
									e.getTrendData().put(k,BigDecimal.valueOf(workTime).divide(BigDecimal.valueOf(planTotal),1,RoundingMode.HALF_UP));
								}
							});
						}
					});
				}
			});
		}
		return result;
	}

	@Override
	public List<CheckStatisticsTrendVO> selectCheckTrendContrastUserWorkDuration(PlanCheckStatisticsQueryDTO queryDTO) {
		List<User> users = userService.listByIds(queryDTO.getUserIds());
		String[] initTypeArr = users.stream().map(User::getRealName).toArray(String[]::new);
		List<CheckStatisticsTrendVO> result = this.initTrendEntirety(queryDTO,initTypeArr);
		List<Long> planIds = baseMapper.selectCheckPlanIds(queryDTO,queryDTO.getUserIds());
		if(Func.isNotEmpty(planIds)){
			List<MaintainPlanUserDayCount> planUserDayCounts = baseMapper.selectByUserDateV2(planIds);
			result.forEach(g -> {
				List<MaintainPlanUserDayCount> groupPlanList = planUserDayCounts.stream().filter(t -> t.getPlanUserNames().contains(String.valueOf(g.getType()))).collect(Collectors.toList());
				if(ObjectUtil.isNotEmpty(groupPlanList)){
					Map<String,List<MaintainPlanUserDayCount>> dateGroup;
					if(queryDTO.getDataType().equals(1)){
						// 日
						dateGroup = groupPlanList.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getPlanDate(),"yyyy/M/d")));
					}else if(queryDTO.getDataType().equals(2)){
						// 周
						dateGroup = groupPlanList.stream().collect(Collectors.groupingBy(t -> String.format("%s~%s",DateUtil.format(DateUtil.beginOfWeek(t.getPlanDate()), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(t.getPlanDate()), "yyyy/M/d"))));
					}else {
						// 月
						dateGroup = groupPlanList.stream().collect(Collectors.groupingBy(t -> String.format("%s月",DateUtil.format(t.getPlanDate(), "yyyy年M"))));
					}
					result.forEach(e -> {
						dateGroup.forEach((k, v) -> {
							if(queryDTO.getTemp().equals(1)){
								// 当前总工单数
								long planTotal = v.stream().filter(t -> t.getPlanUserNames().contains(e.getType())).map(MaintainPlanUserDayCount::getPlanId).distinct().count();
								e.getTrendData().put(k,planTotal);
							}else {
								// 当前总工单数
								long planTotal = v.stream().filter(t -> t.getPlanUserNames().contains(e.getType())).map(MaintainPlanUserDayCount::getPlanId).distinct().count();
								if(planTotal > 0){
									// 当天总时长
									long workTime = v.stream().filter(t -> t.getPlanUserNames().contains(e.getType())).mapToLong(MaintainPlanUserDayCount::getWorkDuration).sum();
									e.getTrendData().put(k,BigDecimal.valueOf(workTime).divide(BigDecimal.valueOf(planTotal),1,RoundingMode.HALF_UP));
								}else {
									e.getTrendData().put(k,0);
								}
							}
						});
					});
				}
			});
		}
		return result;
	}

	@Override
	public Map<String,Object> selectPlanCheckBuildingElevatorPage(IPage<PlanCheckStatisticsBuildingPageVO> page,PlanCheckStatisticsQueryDTO queryDTO) {
		Map<String,Object> resultMap = new HashMap<>();
		List<Long> elevatorIds = new ArrayList<>();
		List<Long> buildingIds = new ArrayList<>();
		// 未设置责任组
		if(queryDTO.getTemp() == 1){
			List<Elevator> elevatorList = baseMapper.selectPlanCheckBuildingElevatorIdsByDept();
			if(Func.isNotEmpty(elevatorList)){
				elevatorIds = elevatorList.stream().map(Elevator::getId).distinct().collect(Collectors.toList());
				buildingIds = elevatorList.stream().map(Elevator::getBuildingId).distinct().collect(Collectors.toList());
			}
		}
		// 未设置责任人
		if(queryDTO.getTemp() == 2){
			List<Elevator> elevatorList = baseMapper.selectPlanCheckBuildingElevatorIdsByUser();
			if(Func.isNotEmpty(elevatorList)){
				elevatorIds = elevatorList.stream().map(Elevator::getId).distinct().collect(Collectors.toList());
				buildingIds = elevatorList.stream().map(Elevator::getBuildingId).distinct().collect(Collectors.toList());
			}
		}
		// 从未排期电梯
		if(queryDTO.getTemp() == 3){
			List<Elevator> elevatorList = baseMapper.selectPlanCheckBuildingElevatorIdsByNotPlan();
			if(Func.isNotEmpty(elevatorList)){
				elevatorIds = elevatorList.stream().map(Elevator::getId).distinct().collect(Collectors.toList());
				buildingIds = elevatorList.stream().map(Elevator::getBuildingId).distinct().collect(Collectors.toList());
			}
		}
		// 无剩余排期
		if(queryDTO.getTemp() == 4){
			List<Elevator> elevatorList = baseMapper.selectPlanCheckBuildingElevatorIdsByNotFeature(queryDTO.getUseType(),queryDTO.getMaintainStatus());
			if(Func.isNotEmpty(elevatorList)){
				elevatorIds = elevatorList.stream().map(Elevator::getId).distinct().collect(Collectors.toList());
				buildingIds = elevatorList.stream().map(Elevator::getBuildingId).distinct().collect(Collectors.toList());
			}
		}
		// 是否违规
		if(queryDTO.getTemp() == 5){
			List<Elevator> elevatorList = baseMapper.selectPlanCheckBuildingElevatorIdsByCompliance(queryDTO.getDeptName(),queryDTO.getCompliance());
			if(Func.isNotEmpty(elevatorList)){
				elevatorIds = elevatorList.stream().map(Elevator::getId).distinct().collect(Collectors.toList());
				buildingIds = elevatorList.stream().map(Elevator::getBuildingId).distinct().collect(Collectors.toList());
			}
		}
		// 从未排期电梯
		if(queryDTO.getTemp() == 6){
			List<Elevator> elevatorList = baseMapper.selectPlanCheckBuildingElevatorIdsByHasFeature();
			if(Func.isNotEmpty(elevatorList)){
				elevatorIds = elevatorList.stream().map(Elevator::getId).distinct().collect(Collectors.toList());
				buildingIds = elevatorList.stream().map(Elevator::getBuildingId).distinct().collect(Collectors.toList());
			}
		}
		if(Func.isNotEmpty(buildingIds)){
			List<PlanCheckStatisticsBuildingPageVO> buildingPage = baseMapper.selectPlanCheckBuildingPage(page,buildingIds);
			List<PlanCheckStatisticsElevatorListVO> elevatorList = baseMapper.selectPlanCheckElevatorList(elevatorIds);
			elevatorList.forEach(e -> {
				List<String> label = new ArrayList<>();
				if(queryDTO.getTemp() == 1){
					label.add("未设置责任组");
				}
				if(queryDTO.getTemp() == 2){
					label.add("未设置责任人");
				}
				if(queryDTO.getTemp() == 3){
					label.add("从未排期电梯");
				}
				if(queryDTO.getTemp() == 4){
					label.add("无剩余排期");
					label.add(ElevatorUseTypeEnum.getName(e.getUserType()));
					label.add(ElevatorMaintainStatusEnums.getName(e.getMaintainStatus()));
				}
				if(queryDTO.getTemp() == 5){
					label.add(queryDTO.getDeptName());
					/**
					 * 若年审梯，保养合规状态：
					 * 正常：今日 < 当前逾期临界日期
					 * 明天即将违规：今日 = 当前逾期临界日期
					 * 已违规：今日 > 当前逾期临界日期
					 */
					int overdueCompare= DateUtil.compare(DateUtil.date(), e.getOverdueDate(), "yyyy-MM-dd");
					if (overdueCompare < 0) {
						label.add(ComplianceStatusEnum.NORMAL.getName());
					} else if (overdueCompare == 0) {
						label.add(ComplianceStatusEnum.VIOLATING.getName());
					} else {
						label.add(ComplianceStatusEnum.VIOLATED.getName());
					}
					label.add(ElevatorMaintainStatusEnums.getName(e.getMaintainStatus()));
					if(overdueCompare > 0){
						long betweenDay = DateUtil.betweenDay(e.getOverdueDate(),DateUtil.date(),Boolean.TRUE);
						label.add(String.format("违规天数：%s天",betweenDay));
					}
				}
				if(queryDTO.getTemp() == 6){
					label.add("已暂停维保");
					label.add("有剩余保养排期");
				}
				e.setLabel(label);
			});
			Map<Long,List<PlanCheckStatisticsElevatorListVO>> buildingGroupMap = elevatorList.stream().collect(Collectors.groupingBy(PlanCheckStatisticsElevatorListVO::getBuildingId));
			buildingPage.forEach(e -> e.setElevatorList(buildingGroupMap.get(e.getBuildingId())));
			page.setRecords(buildingPage);
		}
		resultMap.put("buildingCount",buildingIds.size());
		resultMap.put("elevatorCount",elevatorIds.size());
		resultMap.put("page",page);
		return resultMap;
	}

	/**
	 * 初始化保养趋势整体数据
	 * @param queryDTO
	 * @param initTypeArr
	 * @return
	 */
	private List<CheckStatisticsTrendVO> initTrendEntirety(PlanCheckStatisticsQueryDTO queryDTO, String[] initTypeArr) {
		List<CheckStatisticsTrendVO> initList = new ArrayList<>();
		for (String initType: initTypeArr) {
			CheckStatisticsTrendVO init = new CheckStatisticsTrendVO();
			init.setType(initType);
			Map<String,Object> trendData = new LinkedHashMap<>(32);
			if(queryDTO.getDataType().equals(1)){
				// 日
				List<DateTime> rangeDate = DateUtil.rangeToList(DateUtil.parse(queryDTO.getStartDate()), DateUtil.parse(queryDTO.getEndDate()), DateField.DAY_OF_YEAR);
				rangeDate.forEach(date -> {
					trendData.put(DateUtil.format(date, "yyyy/M/d"), BigDecimal.ZERO);
				});
			}else if(queryDTO.getDataType().equals(2)){
				// 周
				List<DateTime> rangeDate = DateUtil.rangeToList(DateUtil.parse(queryDTO.getStartDate()), DateUtil.parse(queryDTO.getEndDate()), DateField.DAY_OF_YEAR);
				rangeDate.forEach(date -> {
					String weekDate = String.format("%s~%s",DateUtil.format(DateUtil.beginOfWeek(date), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(date), "yyyy/M/d"));
					if (!trendData.containsKey(weekDate)) {
						trendData.put(weekDate,BigDecimal.ZERO);
					}
				});
			}else {
				// 月
				List<DateTime> rangeDate = DateUtil.rangeToList(DateUtil.parse(queryDTO.getStartDate()), DateUtil.parse(queryDTO.getEndDate()), DateField.MONTH);
				rangeDate.forEach(date -> {
					String monthDate = String.format("%s月",DateUtil.format(date, "yyyy年M"));
					trendData.put(monthDate, BigDecimal.ZERO);
				});
			}
			init.setTrendData(trendData);

			initList.add(init);
		}
		return initList;
	}

	/**
	 * 统一获取传参所有userIds
	 * @param queryDTO
	 * @return
	 */
	private List<Long> initDeptUserIds(PlanCheckStatisticsQueryDTO queryDTO) {
		List<Long> userIds = new ArrayList<>();
		queryDTO.getDeptGroups().forEach(e -> userIds.addAll(e.getUserIds()));
		return userIds.stream().distinct().collect(Collectors.toList());
	}

	private void change(CheckPlanUserCountVO result, CheckPlanUserCountVO sign, CheckPlanUserCountVO durationTimeliness) {
		BeanUtil.copyProperties(sign,result, CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
		BeanUtil.copyProperties(durationTimeliness,result, CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
		result.setWorkTime(BigDecimal.valueOf(sign.getWorkTime()/60).setScale(1,RoundingMode.HALF_UP).doubleValue());
		if(result.getPlanCount() > 0){
			result.setWorkTimeAverage(BigDecimal.valueOf(sign.getWorkTime()/result.getPlanCount()).setScale(1,RoundingMode.HALF_UP).doubleValue());
			result.setDisablePer(BigDecimal.valueOf(result.getDisable()/result.getPlanCount()*100L).setScale(1,RoundingMode.HALF_UP).doubleValue());
			result.setProcessedPer(BigDecimal.valueOf(result.getProcessed()/result.getPlanCount()*100L).setScale(1,RoundingMode.HALF_UP).doubleValue());
			result.setCommitPer(BigDecimal.valueOf(result.getCommit()/result.getPlanCount()*100L).setScale(1,RoundingMode.HALF_UP).doubleValue());
			result.setFinishPer(BigDecimal.valueOf(result.getFinish()/result.getPlanCount()*100L).setScale(1,RoundingMode.HALF_UP).doubleValue());
			result.setTimelinessInTimePer(BigDecimal.valueOf(result.getTimelinessInTime()/result.getPlanCount()*100L).setScale(1,RoundingMode.HALF_UP).doubleValue());
			result.setTimelinessOverduePer(BigDecimal.valueOf(result.getTimelinessOverdue()/result.getPlanCount()*100L).setScale(1,RoundingMode.HALF_UP).doubleValue());
		}else {
			result.setWorkTimeAverage(0.00);
			result.setDisablePer(0.00);
			result.setProcessedPer(0.00);
			result.setCommitPer(0.00);
			result.setFinishPer(0.00);
			result.setTimelinessInTimePer(0.00);
			result.setTimelinessOverduePer(0.00);
		}
		if(result.getPlanCommitCount() > 0){
			result.setDurationNormalPer(BigDecimal.valueOf(result.getDurationNormal()/result.getPlanCommitCount()*100L).setScale(1,RoundingMode.HALF_UP).doubleValue());
			result.setDurationTooLongPer(BigDecimal.valueOf(result.getDurationTooLong()/result.getPlanCommitCount()*100L).setScale(1,RoundingMode.HALF_UP).doubleValue());
			result.setDurationTooShortPer(BigDecimal.valueOf(result.getDurationTooShort()/result.getPlanCommitCount()*100L).setScale(1,RoundingMode.HALF_UP).doubleValue());
		}else {
			result.setDurationNormalPer(0.00);
			result.setDurationTooLongPer(0.00);
			result.setDurationTooShortPer(0.00);
		}
		if(result.getSignCount() > 0){
			result.setSignNormalPer(BigDecimal.valueOf(result.getSignNormal()/result.getSignCount()*100L).setScale(1,RoundingMode.HALF_UP).doubleValue());
			result.setSignErrorPer(BigDecimal.valueOf(result.getSignError()/result.getSignCount()*100L).setScale(1,RoundingMode.HALF_UP).doubleValue());
			result.setSignOutErrorPer(BigDecimal.valueOf(result.getSignOutError()/result.getSignCount()*100L).setScale(1,RoundingMode.HALF_UP).doubleValue());
			result.setSignSystemPer(BigDecimal.valueOf(result.getSignSystem()/result.getSignCount()*100L).setScale(1,RoundingMode.HALF_UP).doubleValue());
		}else {
			result.setSignNormalPer(0.00);
			result.setSignErrorPer(0.00);
			result.setSignOutErrorPer(0.00);
			result.setSignSystemPer(0.00);
		}
	}

	public static void main(String[] args) throws ParseException {
		getDatesBetweenByMonth(localDate("2022-07-12"),localDate("2022-08-11")).forEach(date -> {
			System.err.println(DateUtil.format(date,"yyyy-MM"));
		});
//		getDatesBetweenByDay(localDate("2022-06-01"),localDate("2022-06-21")).forEach(date -> {
//			System.err.println(DateUtil.format(date,"yyyy-MM-dd"));
//		});
//		Map<String,Date[]> resultMap = getWeekStartAndEnd("2022-06-19","2022-07-31");
//		resultMap.forEach((s, dates) -> {
//			System.err.println(s+" "+ DateUtil.format(dates[0],"yyyy-MM-dd")+"---"+DateUtil.format(dates[1],"yyyy-MM-dd"));
//		});
//		getWeekStartAndEnd("2022-06-15","2022-07-27");
	}

	/**
	 * 获取指定时间段所有日期
	 * @param startDate
	 * @param endDate
	 * @return
	 */
	public static List<Date> getDatesBetweenByDay(LocalDate startDate, LocalDate endDate) {
		long numOfDaysBetween = ChronoUnit.DAYS.between(startDate, endDate) + 1;
		return IntStream.iterate(0, i -> i + 1)
			.limit(numOfDaysBetween)
			.mapToObj(i -> Date.from(startDate.plusDays(i).atStartOfDay(ZoneId.systemDefault()).toInstant()))
			.collect(Collectors.toList());
	}

	/**
	 * 获取指定时间段所有月份
	 * @param startDate
	 * @param endDate
	 * @return
	 */
	public static List<Date> getDatesBetweenByMonth(LocalDate startDate, LocalDate endDate) {
		LocalDate finalStartDate = startDate.with(TemporalAdjusters.firstDayOfMonth());
		LocalDate finalEndDate = endDate.with(TemporalAdjusters.firstDayOfMonth());
		long numOfDaysBetween = ChronoUnit.MONTHS.between(finalStartDate, finalEndDate) + 1;
		return IntStream.iterate(0, i -> i + 1)
			.limit(numOfDaysBetween)
			.mapToObj(i -> Date.from(finalStartDate.plusMonths(i).atStartOfDay(ZoneId.systemDefault()).toInstant()))
			.collect(Collectors.toList());
	}

	/**
	 * Date 转 LocalDate
	 * @param date yyyy-MM-dd
	 * @return
	 */
	public static LocalDate localDate(Date date) {
		return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
	}

	/**
	 * String 转 LocalDate
	 * @param date yyyy-MM-dd
	 * @return
	 */
	public static LocalDate localDate(String date) {
		return LocalDate.parse(date, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
	}

	/**
	 * 获取时间点所在所有自然周
	 * @param startDate
	 * @param endDate
	 * @return
	 */
	public static Map<String,Date[]> getWeekStartAndEnd(String startDate,String endDate){

		Map<String, Date[]> result = new LinkedHashMap<>();

		final String formatKey = "第%d周";
		Date _start = DateUtil.parse(startDate);
		Date _end = DateUtil.parse(endDate);

		// 获取时间范围自然周第一天和最后一天
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(_start);
		_start = DateUtil.offsetDay(_start,(calendar.get(Calendar.DAY_OF_WEEK)-2)*-1);
		if(calendar.get(Calendar.DAY_OF_WEEK) == 1){
			_start = DateUtil.offsetDay(_start,-7);
		}
		calendar.setTime(_end);
		if(calendar.get(Calendar.DAY_OF_WEEK) > 1){
			_end = DateUtil.offsetDay(_end,Calendar.DAY_OF_WEEK-calendar.get(Calendar.DAY_OF_WEEK)+1);
		}
		List<Date> dates = getDatesBetweenByDay(localDate(_start),localDate(_end));
		int weekIndex = dates.size()/Calendar.DAY_OF_WEEK;
		for (int i = 1; i <= weekIndex; i++) {
			result.put(String.format(formatKey, i),new Date[]{dates.get((i-1)*Calendar.DAY_OF_WEEK),dates.get(i*Calendar.DAY_OF_WEEK-1)});
		}
		return result;
	}

	/**
	 * 根据时间刻度 转化成对应的周
	 * eg: 2021-01-01 - 2020-03-05
	 *
	 * @return {
	 * "2021-01 第一周":['2021-01-01','2021-01-03']
	 * "2021-01 第二周":['2021-01-04','2021-01-10']
	 * ....
	 * "2021-03 第一周":['2021-03-01','2021-03-05']
	 * }
	 */
	public static Map<String, Date[]> getWeekOfMonthStartAndEnd(String startDate, String endDate) {



		Map<String, Date[]> result = new LinkedHashMap<>();

		final int dayTimeOffset = 24 * 60 * 60 * 1000;
		final String formatKey = "%s 第%d周";
		checkNotEmpty(startDate, endDate);
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
		SimpleDateFormat keyFormat = new SimpleDateFormat("yyyy-MM");
		try {
			Date _start = format.parse(startDate);
			Calendar calendar = Calendar.getInstance();
			calendar.setFirstDayOfWeek(Calendar.MONDAY);
			calendar.setTime(_start);
			if (startDate.equals(endDate)) {
				//同一天
				int idx = calendar.get(Calendar.WEEK_OF_MONTH);
				return Collections.singletonMap(String.format(formatKey, startDate.substring(0, 7), idx), new Date[]{_start, _start});
			}
			Date _end = format.parse(endDate);
			//日期偏移量 （日）
			long dayOffset = (_end.getTime() - _start.getTime()) / dayTimeOffset + 1;
			if (dayOffset < 0) {
				throw new IllegalArgumentException("结束时间必须大于开始时间");
			}
			// --------------------------------处理数据-------------------------------//
			// 累加日期
			long spanDay = 0;
			int last;
			do {
				//result Key 值
				//当前在这个月的第几周
				int idx = calendar.get(Calendar.WEEK_OF_MONTH);
				String key = String.format(formatKey, keyFormat.format(calendar.getTime()), idx);
				// 0 星期天 1 周一 2 周二 3 周三 4 周四 5 周五 6 周六
				// 周几
				int week = calendar.get(Calendar.DAY_OF_WEEK) - 1;
				// 当前月最大的天数
				int maxDays = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
				int days = calendar.get(Calendar.DAY_OF_MONTH);
				last = maxDays - days;
				//选择开头的一天
				// value[0]
				Date date1 = calendar.getTime();
				if (week > 0) {
					//这周剩下的几天
					int i = 7 - week;
					//添加剩余的几天  30 31 / 01 ==> add 2 days
					if (i > last) {
						calendar.add(Calendar.DAY_OF_MONTH, last);
						result.put(key, new Date[]{date1, calendar.getTime()});
						// 到达下一个月
						calendar.add(Calendar.DAY_OF_MONTH, 1);
						spanDay = spanDay + last + 1;
					} else if (i + spanDay >= dayOffset) {
						//最后一轮
						result.put(key, new Date[]{date1, _end});
						spanDay = dayOffset;
					} else {
						//添加剩余一整周
						calendar.add(Calendar.DAY_OF_MONTH, i);
						result.put(key, new Date[]{date1, calendar.getTime()});
						spanDay = spanDay + i + 1;
						// 到达下一周周一
						calendar.add(Calendar.DAY_OF_MONTH, 1);
					}
				} else {
					result.put(key, new Date[]{date1, date1});
					// 到达下一周周一
					calendar.add(Calendar.DAY_OF_MONTH, 1);
					spanDay++;
				}
			} while (spanDay < dayOffset);
			return result;
		}catch (ParseException e){
			return result;
		}
	}

	private static void checkNotEmpty(String... args) {
		for (String arg : args) {
			if (StringUtils.isEmpty(arg)) {
				throw new IllegalArgumentException("argument is empty!");
			}
		}
	}
}
